Benar-benar mengetik vue

Logo


inb4: Ini bukan lagi "pengaturan" proyek baru dengan tutorial Vue dan TypeScript. Mari selami topik yang lebih kompleks!


typescript adalah mengagumkan. Vue luar biasa. Tidak diragukan lagi, bahwa banyak orang mencoba untuk menyatukan mereka . Tetapi, karena berbagai alasan, sulit untuk benar - benar mengetik aplikasi Vue Anda. Mari kita cari tahu apa masalahnya dan apa yang bisa dilakukan untuk menyelesaikannya (atau setidaknya meminimalkan dampaknya).


TLDR


Kami memiliki templat yang luar biasa ini dengan Nuxt , Vue , Vuex , dan Vuex diketik sepenuhnya. Cukup instal dan semuanya akan ditanggung untuk Anda. Buka dokumen untuk mempelajari lebih lanjut.


Dan seperti yang saya katakan saya tidak akan memandu Anda melalui pengaturan dasar karena tiga alasan:


  1. Ada banyak tutorial tentang hal itu
  2. Ada banyak alat untuk memulai dengan satu klik seperti Nuxt dan vue-cli dengan plugin typescript
  3. Kami sudah memiliki wemake-vue-template mana setiap bit pengaturan yang akan saya bicarakan sudah dibahas

Pengetikan komponen


Harapan rusak pertama saat Anda mulai bekerja dengan Vue dan typescript dan setelah Anda mengetik komponen kelas Anda adalah bahwa <template> dan <style> masih belum diketik. Izinkan saya menunjukkan kepada Anda sebuah contoh:


 <template> <h1 :class="$style.headr"> Hello, {{ usr }}! </h1> </template> <script lang="ts"> import Vue from 'vue' import Component from 'vue-class-component' import { Prop } from 'vue-property-decorator' @Component({}) export default class HelloComponent extends Vue { @Prop() user!: string } </script> <style module> .header { /* ... */ } </style> 

Saya telah membuat dua kesalahan ketik di sini: {{ usr }} alih-alih {{ user }} dan $style.headr alih-alih $style.header . Apakah typescript akan menyelamatkan saya dari kesalahan ini? Tidak, itu tidak akan terjadi.


Apa yang bisa dilakukan untuk memperbaikinya? Ya, ada beberapa peretasan.


Mengetik template


Orang dapat menggunakan Vetur dengan opsi vetur.experimental.templateInterpolationService untuk mengetik-periksa templat Anda. Ya, ini hanya pemeriksaan berbasis editor dan belum dapat digunakan di dalam CI. Tapi, tim Vetur bekerja keras untuk menyediakan CLI untuk memungkinkan ini. Lacak masalah asli jika Anda tertarik.


vetur


Pilihan kedua adalah dua tes snapshot tulis dengan jest . Ini akan menangkap banyak kesalahan berbasis template. Dan perawatannya cukup murah.


Jadi, kombinasi dari dua alat ini memberi Anda Pengalaman Pengembang yang bagus dengan umpan balik cepat dan cara yang andal untuk menangkap kesalahan di dalam CI.


Gaya mengetik


Mengetik css-module s juga dicakup oleh beberapa alat eksternal:



Gagasan utama alat-alat ini adalah untuk mengambil css-module s dan kemudian membuat file deklarasi .d.ts dari mereka. Maka gaya Anda akan sepenuhnya diketik. Itu masih belum diimplementasikan untuk Nuxt atau Vue , tetapi Anda bisa Nuxt masalah ini untuk kemajuan.


Namun, saya pribadi tidak menggunakan salah satu alat ini dalam proyek saya. Mereka mungkin berguna untuk proyek dengan basis kode besar dan banyak gaya, tapi saya baik-baik saja hanya dengan snapshot.


Styleguides dengan tes regresi visual juga banyak membantu. @storybook/addon-storyshots adalah contoh yang bagus dari teknik ini.


Vuex


Hal besar berikutnya adalah Vuex . Ini memiliki beberapa kompleksitas desain-per-fungsi bawaan untuk mengetik:


 const result: Promise<number> = this.$store.dispatch('action_name', { payload: 1 }) 

Masalahnya adalah 'action_name' mungkin tidak ada, mengambil argumen lain, atau mengembalikan jenis yang berbeda. Itu bukan sesuatu yang Anda harapkan untuk aplikasi yang sepenuhnya diketik.


Apa solusi yang ada?


kelas vuex


vuex-class adalah seperangkat dekorator untuk memungkinkan akses mudah dari komponen berbasis kelas Anda ke internal Vuex .


Tapi, ini tidak diketik aman karena tidak dapat mengganggu jenis negara, getter, mutasi, dan tindakan.


kelas vuex


Tentu saja, Anda dapat secara manual membuat anotasi jenis properti.


vuex-class dijelaskan


Tetapi apa yang akan Anda lakukan ketika tipe negara Anda yang sebenarnya, yang mendapatkan, mutasi, atau tindakan akan berubah? Anda akan memiliki ketidakcocokan tipe tersembunyi.


vuex-sederhana


Di situlah vuex-simple membantu kita. Ini sebenarnya menawarkan cara yang sama sekali berbeda untuk menulis kode Vuex Anda dan itulah yang membuatnya mengetik aman. Mari kita lihat:


 import { Action, Mutation, State, Getter } from 'vuex-simple' class MyStore { // State @State() public comments: CommentType[] = [] // Getters @Getter() public get hasComments (): boolean { return Boolean(this.comments && this.comments.length > 0) } // Mutations @Mutation() public setComments (payload: CommentType[]): void { this.comments = updatedComments } // Actions @Action() public async fetchComments (): Promise<CommentType[]> { // Calling some API: const commentsList = await api.fetchComments() this.setComments(commentsList) // typed mutation return commentsList } } 

Kemudian modul yang diketik ini dapat didaftarkan di dalam Vuex Anda seperti:


 import Vue from 'vue' import Vuex from 'vuex' import { createVuexStore } from 'vuex-simple' import { MyStore } from './store' Vue.use(Vuex) // Creates our typed module instance: const instance = new MyStore() // Returns valid Vuex.Store instance: export default createVuexStore(instance) 

Sekarang kita memiliki instance 100% asli Vuex.Store dan semua jenis informasi yang dibundel dengannya. Untuk menggunakan toko yang diketik ini dalam komponen kita dapat menulis hanya satu baris kode:


 import Vue from 'vue' import Component from 'nuxt-class-component' import { useStore } from 'vuex-simple' import MyStore from './store' @Component({}) export default class MyComponent extends Vue { // That's all we need! typedStore: MyStore = useStore(this.$store) // Demo: will be typed as `Comment[]`: comments = typedStore.comments } 

Sekarang kami telah mengetik Vuex yang dapat digunakan dengan aman di dalam proyek kami.
Ketika kami mengubah sesuatu di dalam definisi toko kami, itu secara otomatis tercermin ke komponen yang menggunakan toko ini. Jika sesuatu gagal - kami mengetahuinya sesegera mungkin.


Ada juga berbagai pustaka yang melakukan hal yang sama tetapi memiliki API yang berbeda. Pilih yang paling cocok untuk Anda.


Panggilan API


Ketika kita sudah Vuex dengan benar, kita perlu mengisinya dengan data.
Mari kita lihat definisi tindakan kita lagi:


 @Action() public async fetchComments (): Promise<CommentType[]> { // Calling some API: const commentsList = await api.fetchComments() // ... return commentsList } 

Bagaimana kita bisa tahu bahwa itu benar-benar akan mengembalikan daftar CommentType dan bukan number tunggal atau sekelompok contoh AuthorType ?


Kami tidak dapat mengontrol server. Dan server mungkin benar-benar melanggar kontrak. Atau kita bisa dengan mudah mengirimkan contoh api salah, membuat salah ketik di URL, atau apa pun.


Bagaimana kita bisa selamat? Kita bisa menggunakan ketikan runtime! Izinkan saya memperkenalkan io-ts kepada Anda:


 import * as ts from 'io-ts' export const Comment = ts.type({ 'id': ts.number, 'body': ts.string, 'email': ts.string, }) // Static TypeScript type, that can be used as a regular `type`: export type CommentType = ts.TypeOf<typeof Comment> 

Apa yang kita lakukan di sini?


  1. Kami mendefinisikan turunan ts.type dengan bidang yang perlu kami periksa saat runtime ketika kami menerima respons dari server
  2. Kami mendefinisikan jenis statis untuk digunakan dalam anotasi tanpa pelat tambahan

Dan nanti kita bisa menggunakannya panggilan api kita:


 import * as ts from 'io-ts' import * as tPromise from 'io-ts-promise' public async fetchComments (): Promise<CommentType[]> { const response = await axios.get('comments') return tPromise.decode(ts.array(Comment), response.data) } 

Dengan bantuan io-ts-promise , kami dapat mengembalikan Promise dalam keadaan gagal jika respons dari server tidak cocok dengan ts.array(Comment) . Ini benar-benar berfungsi seperti validasi.


 fetchComments() .then((data) => /* ... */ .catch(/* Happens with both request failure and incorrect response type */) 

Selain itu, anotasi jenis pengembalian disinkronkan dengan metode .decode . Dan Anda tidak dapat menempatkan omong kosong acak di sana:


io-ts


Dengan kombinasi runtime dan pemeriksaan statis, kami dapat memastikan bahwa permintaan kami tidak akan gagal karena jenis ketidakcocokan.
Tetapi, untuk menjadi 100% yakin bahwa semuanya berfungsi, saya akan merekomendasikan menggunakan pengujian berbasis kontrak: lihat pact sebagai contoh. Dan pantau aplikasi Anda dengan Sentry .


Router Vue


Masalah selanjutnya adalah this.$router.push({ name: 'wrong!' }) Tidak berfungsi seperti yang kita inginkan.


Saya akan mengatakan bahwa akan sangat ideal untuk diperingatkan oleh kompiler bahwa kita melakukan routing ke arah yang salah dan rute ini tidak ada.
Tapi itu tidak mungkin. Dan tidak banyak yang bisa dilakukan: ada banyak rute dinamis, regex, fallback, izin, dll yang pada akhirnya dapat rusak. Satu-satunya pilihan adalah menguji masing-masing this.$router Panggilan this.$router di aplikasi Anda.


vue-test-utils


Berbicara tentang tes, saya tidak punya alasan untuk tidak menyebutkan @vue/test-utils yang juga memiliki beberapa masalah dengan pengetikan.


Ketika kami akan mencoba menguji komponen mengkilap baru kami dengan properti typedStore , kami akan mengetahui bahwa kami sebenarnya tidak dapat melakukannya sesuai dengan typescript :


vue-test-utils


Mengapa ini terjadi? Ini terjadi karena panggilan mount() tidak tahu apa-apa tentang tipe komponen Anda, karena semua komponen memiliki VueConstructor<Vue> secara default:


vue-constructor


Di situlah semua masalah berasal. Apa yang bisa dilakukan?
Anda dapat menggunakan vuetype untuk menghasilkan YouComponent.vue.d.ts YouComponent.vue.d.ts yang akan memberi tahu tes Anda tipe yang tepat dari komponen yang dipasang.


Anda juga dapat melacak masalah ini untuk kemajuannya.


Tapi saya tidak suka ide ini. Ini adalah tes, mereka bisa gagal. Bukan masalah besar.
Itu sebabnya saya tetap berpegang pada (wrapper.vm as any).whatever pendekatannya. Ini menghemat banyak waktu untuk menulis tes. Tetapi rampasan Pengalaman Pengembang sedikit.


Buat keputusan sendiri di sini:


  • Gunakan vuetype sepanjang jalan
  • Terapkan sebagian ke komponen yang paling penting dengan jumlah tes terbesar dan perbarui secara teratur
  • Gunakan any sebagai cadangan

Kesimpulan


Tingkat rata-rata dukungan typescript dalam ekosistem Vue meningkat selama beberapa tahun terakhir:


  • Nuxt pertama kali memperkenalkan nuxt-ts dan sekarang mengirimkan ts secara default
  • Vue@3 akan memiliki dukungan typescript ditingkatkan
  • Lebih banyak aplikasi dan plugin pihak ketiga akan memberikan definisi jenis

Tapi, saat ini sudah siap berproduksi. Ini hanya hal-hal untuk ditingkatkan! Menulis kode Vue tipe-aman benar-benar meningkatkan Pengalaman Pengembang Anda dan memungkinkan Anda untuk fokus pada hal-hal penting sambil meninggalkan beban berat ke kompiler.


Apa retas dan alat favorit Anda untuk mengetik aplikasi Vue ? Mari kita bahas di bagian komentar.

Source: https://habr.com/ru/post/id458632/


All Articles