
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:
- Ada banyak tutorial tentang hal itu
- Ada banyak alat untuk memulai dengan satu klik seperti
Nuxt
dan vue-cli
dengan plugin typescript
- 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.

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.

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

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?
- Kami mendefinisikan turunan
ts.type
dengan bidang yang perlu kami periksa saat runtime ketika kami menerima respons dari server - 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:

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
:

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

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 defaultVue@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.