您好,登錄后才能下訂單哦!
Vue中TypeScript的使用方法,針對這個問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
Vue.extend or vue-class-component
使用 TypeScript 寫 Vue 組件時,有兩種推薦形式:
Vue.extend()
:使用基礎(chǔ) Vue 構(gòu)造器,創(chuàng)建一個“子類”。此種寫法與 Vue 單文件組件標(biāo)準(zhǔn)形式最為接近,唯一不同僅是組件選項(xiàng)需要被包裹在 Vue.extend()
中。
vue-class-component
:通常與 vue-property-decorator
一起使用,提供一系列裝飾器,能讓我們書寫類風(fēng)格的 Vue 組件。
兩種形式輸出結(jié)果一致,同是創(chuàng)建一個 Vue 子類,但在書寫組件選項(xiàng)如 props,mixin 時,有些不同。特別是當(dāng)你使用 Vue.extend()
時,為了讓 TypeScript 正確推斷類型,你將不得不做一些額外的處理。接下來,我們來聊一聊它們的細(xì)節(jié)差異。
Prop
由于組件實(shí)例的作用域是孤立的,當(dāng)從父組件傳遞數(shù)據(jù)到子組件時,我們通常使用 Prop 選項(xiàng)。同時,為了確保 Prop 的類型安全,我們會給 Prop 添加指定類型驗(yàn)證,形式如下:
export default { props: { someProp: { type: Object, required: true, default: () => ({ message: 'test' }) } } }
我們定義了一個 someProp,它的類型是 Object。
使用 JavaScript 時,這并沒有什么不對的地方,但當(dāng)你使用 TypeScript 時,這有點(diǎn)不足,我們并不能得到有關(guān)于 someProp 更多有用的信息(比如它含有某些屬性),甚至在 TypeScript 看來,這將會是一個 any 類型:
這意味著我們可以使用 someProp 上的任意屬性(存在或者是不存在的)都可以通過編譯。為了防止此種情況的發(fā)生,我們將會給 Prop 添加類型注釋。
Vue.extend()
使用 Vue.extend()
方法添加類型注釋時,需要給 type 斷言:
import Vue from 'vue' interface User { name: string, age: number } export default Vue.extend({ props: { testProps: { type: Object as () => User } } })
當(dāng)組件內(nèi)訪問 testProps 時,便能得到相關(guān)提示:
然而,你必須以函數(shù)返回值的形式斷言,并不能直接斷言:
export default Vue.extend({ props: { testProps: { type: Object as User } } })
它會給出錯誤警告,User 接口并沒有實(shí)現(xiàn)原生 Object 構(gòu)造函數(shù)所執(zhí)行的方法:
Type 'ObjectConstructor' cannot be converted to type 'User'. Property 'id' is missing in type 'ObjectConstructor'.
實(shí)際上,我們可從 Prop type declaration :
export type Prop<T> = { (): T } | { new (...args: any[]): T & object } export type PropValidator<T> = PropOptions<T> | Prop<T> | Prop<T>[]; export interface PropOptions<T=any> { type?: Prop<T> | Prop<T>[]; required?: boolean; default?: T | null | undefined | (() => object); validator?(value: T): boolean; }
可知 Prop type 可以以兩種不同方式出現(xiàn):
含有一個調(diào)用簽名的范型 type,該簽名返回 T;
一個范型構(gòu)造函數(shù)簽名,該函數(shù)創(chuàng)建指定類型 T 對象 (返回值 T & object
用于降低優(yōu)先級,當(dāng)兩種方式同時滿足時取第一種,其次它還可以用于標(biāo)記構(gòu)造函數(shù)不應(yīng)該返回原始類型)。
當(dāng)我們指定 type 類型為 String/Number/Boolean/Array/Object/Date/Function/Symbol 等原生構(gòu)造函數(shù)時,Prop<T> 會返回它們各自簽名的返回值。
當(dāng) type 類型為 String 構(gòu)造函數(shù)時,它的調(diào)用簽名返回為 string:
// lib.es5.d.ts interface StringConstructor { new(value?: any): String; (value?: any): string; readonly prototype: String; fromCharCode(...codes: number[]): string; }
而這也是上文中,當(dāng)指定 type 類型為 Object 構(gòu)造函數(shù)時,經(jīng)過 Vue 的聲明文件處理,TypeScript 推斷出為 any 類型的原因:
interface ObjectConstructor { new(value?: any): Object; (): any; (value: any): any; // 其它屬性 .... }
類似的,當(dāng)我們使用關(guān)鍵字 as
斷言 Object 為 () => User
時,它能推斷出為 User 。
從 type 第二部分可知,除傳入原生構(gòu)造函數(shù)外,我們還可傳入自定義類:
此外,這里有個 PR 暴露一個更直觀的類型( Vue 2.6 版本才可以用):
props: { testProp: Object as PropTypes<{ test: boolean }> }
vue-class-component
得益于 vue-propperty-decorator Prop 修飾器,當(dāng)給 Prop 增加類型推斷時,這些將變得簡單:
import { Component, Vue, Prop } from 'vue-property-decorator' @Component export default class Test extends Vue { @Prop({ type: Object }) private test: { value: string } }
當(dāng)我們在組件內(nèi)訪問 test
時,便能獲取它正確的類型信息。
mixins
mixins 是一種分發(fā) Vue 組件中可復(fù)用功能的一種方式。當(dāng)在 TypeScript 中使用它時,我們希望得到有關(guān)于 mixins 的類型信息。
當(dāng)你使用 Vue.extends()
時,這有點(diǎn)困難,它并不能推斷出 mixins 里的類型:
// ExampleMixin.vue export default Vue.extend({ data () { return { testValue: 'test' } } }) // other.vue export default Vue.extend({ mixins: [ExampleMixin], created () { this.testValue // error, testValue 不存在! } })
我們需要稍作修改:
// other.vue export default ExampleMixin.extend({ mixins: [ExampleMixin], created () { this.testValue // 編譯通過 } })
但這會存在一個問題,當(dāng)使用多個 mixins 且推斷出類型時,這將無法工作。而在這個 Issuse 中官方也明確表示,這無法被修改。
使用 vue-class-component 這會方便很多:
// ExampleMixin.vue import Vue from 'vue' import Component from 'vue-class-component' @Component export class ExampleMixin extends Vue { public testValue = 'test' } // other.vue import Component, { mixins } from 'vue-class-component' import ExampleMixin from 'ExampleMixin.vue' @Component({ components: { ExampleMixin } }) export class MyComp extends mixins(ExampleMixin) { created () { console.log(this.testValue) // 編譯通過 } }
也支持可以傳入多個 mixins。
一些其它
做為 Vue 中最正統(tǒng)的方法(與標(biāo)準(zhǔn)形式最為接近),Vue.extends()
有著自己的優(yōu)勢,在 VScode Vetur 插件輔助下,它能正確提示子組件上的 Props:
而類做為 TypeScript 特殊的存在(它既可以作為類型,也可以作為值),當(dāng)我們使用 vue-class-component
并通過 $refs
綁定為子類組件時,便能獲取子組件上暴露的類型信息:
導(dǎo)入 .vue 時,為什么會報錯?
當(dāng)你在 Vue 中使用 TypeScript 時,所遇到的第一個問題即是在 ts 文件中找不到 .vue 文件,即使你所寫的路徑并沒有問題:
在 TypeScript 中,它僅識別 js/ts/jsx/tsx 文件,為了讓它識別 .vue 文件,我們需要顯式告訴 TypeScript,vue 文件存在,并且指定導(dǎo)出 VueConstructor:
declare module '*.vue' { import Vue from 'vue' export default Vue }
但是,這引起了另一個問題,當(dāng)我們導(dǎo)入一個并不存在的 .vue 文件時,也能通過編譯:
是的,這在情理之中。
當(dāng)我嘗試在 .vue 文件中導(dǎo)入已存在或者不存在的 .vue 文件時,卻得到不同的結(jié)果:
文件不存在時:
文件存在時:
關(guān)于Vue中TypeScript的使用方法問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。