Vue 中使用 typescript的方法詳解
什么是typescript
typescript 為 javaScript的超集,這意味著它支持所有都JavaScript都語(yǔ)法。它很像JavaScript都強(qiáng)類(lèi)型版本,除此之外,它還有一些擴(kuò)展的語(yǔ)法,如interface/module等。 typescript 在編譯期會(huì)去掉類(lèi)型和特有語(yǔ)法,生成純粹的JavaScript。
Typescript 5年內(nèi)的熱度隨時(shí)間變化的趨勢(shì),整體呈現(xiàn)一個(gè)上升的趨勢(shì)。也說(shuō)明ts越來(lái)越️受大家的關(guān)注了。
安裝typescript
npm install -g typescript tsc greeter.ts
舉個(gè)栗子
左右對(duì)比可以看出typescript 在編譯期會(huì)去掉類(lèi)型和特有語(yǔ)法,生成純粹的JavaScript。 greeter.ts
interface Person { firstName: string; lastName: string; } function greeter(person: Person) { return "Hello, " + person.firstName + " " + person.lastName; } let user = { firstName: "Jane", lastName: "User" };
greeter.js
function greeter(person) { return "Hello, " + person.firstName + " " + person.lastName; } var user = { firstName: "Jane", lastName: "User" };
為什么需要使用它?
優(yōu)勢(shì):
- 靜態(tài)類(lèi)型檢查
- IDE 智能提示
- 代碼重構(gòu)
- 可讀性
1. 靜態(tài)類(lèi)型檢查
靜態(tài)類(lèi)型檢查首要優(yōu)點(diǎn)就是能盡早的發(fā)現(xiàn)邏輯錯(cuò)誤,而不是上線之后才發(fā)現(xiàn)。
1.1 類(lèi)型分析
傳參過(guò)程字段錯(cuò)誤,或類(lèi)型錯(cuò)誤使用。(進(jìn)行參數(shù)標(biāo)注后,在編碼過(guò)程中即可檢查出錯(cuò)誤。)
1.2 類(lèi)型推斷:函數(shù)的返回值可通過(guò)ts類(lèi)型推斷得出.這一步驟是 在編譯時(shí)進(jìn)行在編譯時(shí)進(jìn)行類(lèi)型分析
example: eg1: 我在使用ts寫(xiě)vue-router 的 動(dòng)態(tài)路徑參數(shù)時(shí)就發(fā)現(xiàn)了一個(gè)問(wèn)題, 動(dòng)態(tài)路徑參數(shù) 以冒號(hào)開(kāi)頭 path: '/user/:id',我們會(huì)誤認(rèn)為id為一個(gè)number,如果使用ts你將得到提示 我們應(yīng)該傳入一個(gè)string類(lèi)型的id. 傳入一個(gè)number類(lèi)型的id可能并不會(huì)出錯(cuò),js會(huì)對(duì)它進(jìn)行隱式類(lèi)型轉(zhuǎn)換,但是傳入一個(gè)string會(huì)使它更安全和規(guī)范.
eg2: 個(gè)人使用后的效果
interface Person { firstName: string; lastName: string; } function greeter(person: Person): string { return "Hello, " + person.firstName + " " + person.lastName; } let user = { firstName: 1223, lastname: "User" }; greeter(user);
2.智能補(bǔ)全
在編寫(xiě)代碼時(shí)ide就會(huì)提示函數(shù)簽名.
interface Person { firstName: string; lastName: string; } /** * 問(wèn)候語(yǔ)句 * @param {Person} person * @returns {string} */ function greeter(person: Person): string { return "Hello, " + person.firstName + " " + person.lastName; } /** * hello word! * * @param {string} word * @returns {string} */ function Hello(word: string): string { return "hello," + word; } export { greeter, Hello };
直接將這個(gè)ts文件引入到其他ts文件中,不僅補(bǔ)全了所有的參數(shù)類(lèi)型,還告訴你需要填入一個(gè)參數(shù),并且你只有填入一個(gè)Person類(lèi)型的對(duì)象才不會(huì)報(bào)錯(cuò)。(智能補(bǔ)全和參數(shù)校驗(yàn))
3.在重構(gòu)上
動(dòng)態(tài)一時(shí)爽,重構(gòu)火葬場(chǎng).
typescript 在重構(gòu)上的優(yōu)勢(shì),我們主要從三方面說(shuō)明。
- 重命名符號(hào),可將一切引用的地方都進(jìn)行修改。
- 在vs code 中如果我們想修改函數(shù)、變量或者類(lèi)的名稱(chēng),我們可以使用重命名符號(hào)的功能,在當(dāng)前項(xiàng)目中正確的修改所有的引用.這個(gè)既可以在ts中使用,也可以在js中使用,而它的底層實(shí)現(xiàn)都是依靠ts 的語(yǔ)法分析器實(shí)現(xiàn)的。
- 自動(dòng)更新引用路徑(vs code)。
- 在重構(gòu)的過(guò)程中,我們可能需要移動(dòng)文件的路徑,這往往會(huì)導(dǎo)致其他地方的import失效,這時(shí)候vs code提供了自動(dòng)更新引用路徑的功能。它的底層實(shí)現(xiàn)也是依靠ts 的語(yǔ)法分析器實(shí)現(xiàn)的。
- 校驗(yàn)函數(shù)簽名。
有時(shí)候我們會(huì)重構(gòu)類(lèi)或函數(shù)的簽名,如果有引用到的地方忘記修改,除了運(yùn)行時(shí)候能發(fā)現(xiàn),其他時(shí)候往往難以察覺(jué),且 ESLint 也只能是排查簡(jiǎn)單的問(wèn)題,所以出了BUG會(huì)非常麻煩。 而 TypeScript 不一樣,在編碼時(shí)就能及時(shí)的發(fā)現(xiàn)哪里錯(cuò)了,哪里應(yīng)該改動(dòng)但沒(méi)有修改。
[函數(shù)簽名 MDN][5]
4. 可讀性
可讀性上,TypeScript 明顯占優(yōu),查看開(kāi)源代碼時(shí),如果注釋不是很完善,往往會(huì)看的云里霧里,而 TypeScript 在同等條件下,至少有個(gè)類(lèi)型,能讓自己更容易明白代碼的參數(shù)、返回值和意圖。
TS+Vue初探
配置
在正式開(kāi)發(fā)之前,我們需要了解一些基本的配置。
1.tsconfig.json 是 ts 項(xiàng)目的編譯選項(xiàng)配置文件. 在 ts 項(xiàng)目中如果你不添加這份文件,ts 會(huì)使用默認(rèn)的配置. 掃描二維碼獲取配置項(xiàng)目。
- ts-loader:Webpack 的TypeScript 加載器,就是為了讓 webpack 編譯 .ts .tsx文件。
- TSLint:.ts .tsx文件的代碼風(fēng)格檢查工具。(作用類(lèi)似于ESLint)
- vue-shim.d.ts:由于 TypeScript 默認(rèn)并不支持 *.vue 后綴的文件,所以在 vue 項(xiàng)目中引入的時(shí)候需要?jiǎng)?chuàng)建一個(gè) vue-shim.d.ts 文件,放在項(xiàng)目根目錄下,例如 src/vue-shim.d.ts。
在Vue里面寫(xiě)TS的方式
圖中內(nèi)容應(yīng)寫(xiě)在script中的lang="ts" 。
上圖:使用 Vue.extend的基礎(chǔ)用法。
下
圖:基于類(lèi)的Vue組件
通過(guò)
對(duì)比我們發(fā)現(xiàn),上面的編碼方式更接近我們平時(shí)JS的寫(xiě)法,但是我們并不能感受到ts的類(lèi)型檢查和類(lèi)型推斷。下面張圖的寫(xiě)法更有助于我們得到ts的類(lèi)型檢查。這需要我們引入 vue-class-component ,雖然template中還是不能得到補(bǔ)全,但是script 中的內(nèi)容得到了更好的補(bǔ)全。 下面我們了解一下vue-class-component的作用。
vue-class-component & vue-property-decorator
vue-class-component 強(qiáng)化 Vue 組件,使用裝飾器語(yǔ)法使 Vue 組件更好的跟TS結(jié)合使用。 vue-property-decorator在 vue-class-component 的基礎(chǔ)上增加了更多與 Vue 相關(guān)的裝飾器,使Vue組件更好的跟TS結(jié)合使用。
這兩者都是離不開(kāi)裝飾器的,(decorator)裝飾器已在ES提案中。Decorator是裝飾器模式的實(shí)踐。裝飾器模式呢,它是繼承關(guān)系的一個(gè)替代方案。動(dòng)態(tài)地給對(duì)象添加額外的職責(zé)。在不改變接口的前提下,增強(qiáng)類(lèi)的性能。下面我們以 鋼鐵俠 為例講解如何使用 ES7 的 decorator。
以鋼鐵俠為例,鋼鐵俠本質(zhì)是一個(gè)人,只是“裝飾”了很多武器方才變得那么 NB,不過(guò)再怎么裝飾他還是一個(gè)人,它本質(zhì)是沒(méi)有被改變的。所以,裝飾器沒(méi)有改變其繼承關(guān)系,但也同樣能夠?yàn)樗砑雍芏鄥柡Φ募寄堋:?jiǎn)單的說(shuō),裝飾器是在不修改一個(gè)類(lèi)的繼承關(guān)系的前提下,為一個(gè)類(lèi)修改或添加成員。
裝飾器主要接收的三個(gè)參數(shù): target 要在其上定義屬性的對(duì)象。 key 要定義或修改的屬性的名稱(chēng)。 descriptor 將被定義或修改的屬性描述符。下面我們通過(guò)代碼中我們?yōu)橐粋€(gè)人添加了飛行的功能:
typescript VS JavaScript
了解了上面的基礎(chǔ)知識(shí),現(xiàn)在我將同一段代碼分別使用js 和 ts來(lái)書(shū)寫(xiě),現(xiàn)在我們來(lái)對(duì)比他們之間的差別。
Props (Properties) 使用js,我們有很多中方式來(lái)定義組件的 Props,但是大多都摻雜了 Vue 的私有特征,與 ES 格格不入,例如左邊的代碼,明明我們是把這個(gè)對(duì)象的 prop 屬性定義成為了一個(gè)包含兩個(gè) string 元素的對(duì)象,但是我們卻可以直接通過(guò)這個(gè)對(duì)象來(lái)訪問(wèn) "name" 字段,這很明顯是不符合 ES 語(yǔ)義的。再來(lái)看看右邊的 TS 選手,通過(guò) Prop 裝飾器把指定的字段標(biāo)記為了 Prop,既保留了 ES 語(yǔ)法的語(yǔ)義,而且還能與 Vue 完美的配合,更棒的是,我們可以在編碼的過(guò)程中享受 TS 對(duì) Prop 字段的靜態(tài)類(lèi)型檢查。Method 和 data 再來(lái)看看 Method,JS 中定義 method 還是有我們上面提到的那個(gè)不符合 ES 語(yǔ)義的毛病。而在 TS 中,method 不需要額外的裝飾器——實(shí)例方法就會(huì)自動(dòng)成為 Vue 組件的 method。類(lèi)似的還有 data ,使用 TS 的語(yǔ)法,實(shí)例字段即可自動(dòng)成為 Vue 組件的 data。Computed 在傳統(tǒng)的使用 JS 編寫(xiě)的 Vue 代碼中,如果要定義計(jì)算屬性,我們需要在 computed 屬性中定義相應(yīng)的函數(shù)。而這在 ES 中其實(shí)早就已經(jīng)有了對(duì)應(yīng)語(yǔ)義的語(yǔ)法——getter,所以在使用了 vue-class-component 的 vue 組件中,我們可以直接使用 getter 來(lái)定義計(jì)算屬性,不管是在語(yǔ)法上還是在語(yǔ)義上,相比普通的 JS 都略勝一籌
總結(jié):我們使用vue-class-component讓vue組件的定義更加符合ES語(yǔ)義,使得TS能夠更好的進(jìn)行語(yǔ)法分析,并基于此進(jìn)行類(lèi)型檢查。
業(yè)務(wù)場(chǎng)景中使用TS + Vue
1. 在Vue項(xiàng)目中定義data和props
這樣的寫(xiě)法,讓我產(chǎn)生了兩個(gè)疑惑。
1.1 為什么使用 的寫(xiě)法 @Prop(Number!:) propA!: number 而不是 @Prop(Number) propA: number
1.2 為什么Prop需要前后寫(xiě)兩次類(lèi)型?
自我自答環(huán)節(jié):
答1.1:因?yàn)槲覀兌ㄒ粋€(gè)Phone這個(gè)類(lèi),沒(méi)有對(duì)phone、condition這些字段通過(guò)constructor進(jìn)行初始化,所以需要在屬性上使用 顯式賦值斷言來(lái)幫助類(lèi)型系統(tǒng)識(shí)別類(lèi)型,這樣能夠讓屬性會(huì)被間接地初始化。答1.2:前面括號(hào)里面的類(lèi)型標(biāo)注是Vue提供的類(lèi)型檢查。冒號(hào)后面的是為T(mén)S提供的類(lèi)型標(biāo)注。
2. 編寫(xiě)一個(gè)函數(shù)
這里我們將使用到j(luò)s的接口,它經(jīng)常用于定義復(fù)雜的參數(shù)類(lèi)型和返回值類(lèi)型。
上面的例子,我們需要為opts這個(gè)參數(shù)定義類(lèi)型,方便后面編碼時(shí)的使用,這時(shí)我們就需要編寫(xiě)一個(gè)接口來(lái)對(duì)它進(jìn)行類(lèi)型定義。這個(gè)接口里面包括三個(gè)必須屬性和一個(gè)可選屬性。必須屬性在對(duì)象初始化的時(shí)候必須賦值,但是有時(shí)候某個(gè)對(duì)象中的屬性可以被忽略的,不一定會(huì)被需要。我們可以將它設(shè)置為可選項(xiàng)。
隨著業(yè)務(wù)的發(fā)展,一些參數(shù)的字段會(huì)變的越來(lái)越多,越來(lái)越復(fù)雜??赡苣阆胗袥](méi)有什么一勞永逸的方法,讓接口更加簡(jiǎn)單,甚至讓它自動(dòng)的適應(yīng)業(yè)務(wù)的變化。于是我想出了這樣的代碼:
上面的代碼: 定義了一個(gè)鍵為string,他的值為number或string類(lèi)型的接口,并且該接口的所有字段都是可選的,你甚至可以傳入一個(gè)空對(duì)象。所以我們可以使用上面的接口可以代替下面的接口,但是反之不行.
然而我們不應(yīng)該去繞開(kāi)這些檢查,因?yàn)檫@樣ts就不會(huì)為你檢查使用接口的對(duì)象應(yīng)該存在那些屬性或者方法了。使用ts的意義就被大大減弱了。
3. 編寫(xiě)第三方依賴(lài)
在日常的開(kāi)發(fā)過(guò)程中,我們經(jīng)常會(huì)遇到將第三方依賴(lài)引入到 TS 項(xiàng)目中沒(méi)有類(lèi)型檢查的問(wèn)題,這往往是因?yàn)檫@些項(xiàng)目沒(méi)有提供類(lèi)型定義文件。這個(gè)時(shí)候,我們可以手動(dòng)為這些第三方庫(kù)編寫(xiě)類(lèi)型定義文件,類(lèi)型定義文件在編譯后會(huì)被完全忽略,所以并不會(huì)對(duì)現(xiàn)有代碼產(chǎn)生影響。以上面這個(gè)較為復(fù)雜的函數(shù)為例,它的作用是將傳入的所有的參數(shù)的所有字段合并到一個(gè)新的對(duì)象中并返回,盡管他的功能比較簡(jiǎn)單,但是為它編寫(xiě)類(lèi)型定義還是需要一些 TS 的技巧。
1. 外部模塊聲明: 首先我們需要?jiǎng)?chuàng)建一個(gè)拓展名為 .d.ts 的文件,并在其中聲明一個(gè)模塊,聲明的模塊名稱(chēng)需要跟我們?cè)谄渌募幸氲穆窂较嗤?/p>
2. 類(lèi)型參數(shù)——泛型:首先讓我們考慮最簡(jiǎn)單的情況,當(dāng)傳入一個(gè)參數(shù)的時(shí)候,extend 函數(shù)應(yīng)該返回與參數(shù)類(lèi)型相同的對(duì)象,但是我們?cè)诰帉?xiě)函數(shù)的時(shí)候并不知道用戶(hù)會(huì)傳入何種類(lèi)型的參數(shù),所以我們可以定義一個(gè)類(lèi)型參數(shù) T1,這時(shí),extend 就被稱(chēng)為泛型函數(shù),T1 也被稱(chēng)做泛型參數(shù)。在上面的例子中,extend 函數(shù)接受一個(gè)類(lèi)型為 T1 參數(shù)并返回一個(gè)類(lèi)型為 T1 的值,T1 需要用戶(hù)手動(dòng)傳入,還好 TS 足夠聰明,在絕大多數(shù)情況下,TS 可以根據(jù)參數(shù)類(lèi)型來(lái)自動(dòng)推斷類(lèi)型參數(shù),免去了我們輸入類(lèi)型參數(shù)的繁瑣步驟。只接受一個(gè)參數(shù)的 extend 函數(shù)并沒(méi)有很復(fù)雜,我們可以繼續(xù)考慮一些更復(fù)雜的情況。
這次讓我們定義一個(gè)接受三個(gè)參數(shù)的 extend 函數(shù),同時(shí)它也接受三個(gè)泛型參數(shù),而它返回值類(lèi)型呢,則是 T1, T2, T3 的交叉類(lèi)型。交叉類(lèi)型讓我們可以把現(xiàn)有的多種類(lèi)型疊加到一起成為一種類(lèi)型,它包含了所需的所有類(lèi)型的特性,相當(dāng)于對(duì)這些類(lèi)型的成員求并集。 例如, T1 & T2 & T3 這個(gè)類(lèi)型的對(duì)象同時(shí)擁有了這三種類(lèi)型的成員。在這里,交叉類(lèi)型就滿(mǎn)足了我們對(duì) extend 函數(shù)返回值類(lèi)型的要求。值得注意的是,實(shí)際的 extend 函數(shù)可以接受不定個(gè)數(shù)的參數(shù),也就是說(shuō),我們?yōu)樗帉?xiě)的類(lèi)型定義也需要同時(shí)兼容接受不定個(gè)數(shù)參數(shù)的情況,這就需要 TS 提供的函數(shù)重載功能。
3. 重載:在大多數(shù)靜態(tài)類(lèi)型編程語(yǔ)言中,編譯器允許存在參數(shù)類(lèi)型、個(gè)數(shù)不同的多個(gè)同名函數(shù),這個(gè)特性被稱(chēng)為函數(shù)重載。TS 支持函數(shù)重載的特性,所以我們可以定義多個(gè)接受不同數(shù)量參數(shù)的 extend 方法,在用戶(hù)調(diào)用時(shí),TS 會(huì)自動(dòng)的在這些同名函數(shù)中選擇正確的重載定義。有了函數(shù)重載的幫助,我們可以在使用 extend 的大多數(shù)場(chǎng)景下享受到類(lèi)型檢查的好處,只有在參數(shù)個(gè)數(shù)超過(guò)4個(gè)的時(shí)候,TS 才無(wú)法推斷出返回值類(lèi)型。需要注意的是在 JS 中,運(yùn)行時(shí)并不提供函數(shù)重載的能力,我們無(wú)法定義多個(gè)同名函數(shù),即使他們接受的參數(shù)數(shù)量并不相同,為了實(shí)現(xiàn)函數(shù)重載的效果,開(kāi)發(fā)人員需要手動(dòng)在單個(gè)函數(shù)中對(duì)參數(shù)的類(lèi)型、數(shù)量做出判斷。
到這里我們的第三方聲明就完成了,即使一個(gè)簡(jiǎn)單函數(shù)的第三方聲明,我們也運(yùn)用了很多ts的相關(guān)知識(shí)。
個(gè)人感受
前面我們講解了,使用在vue中使用ts能帶給我們的種種便利,現(xiàn)在就我個(gè)人感受而言,說(shuō)一下美中不足的地方。
1.即使使用了ts,template 部分仍沒(méi)有靜態(tài)類(lèi)型檢查和IDE智能提示,但官方成員表示在以后的 Vue 單文件中會(huì)提供這項(xiàng)功能。 2.將 Vue 單文件組件引入 TS 文件中,無(wú)法正確的提示其文件位置。 3.Vue 周邊工具,比如 Vuex,它對(duì)ts的支持薄弱,大量的功能難以直接遷移到ts中,并且沒(méi)有好的官方支持的方案。 4.毫無(wú)疑問(wèn),使用 TS 進(jìn)行開(kāi)發(fā),相比于 JS ,我們需要花費(fèi)更多的時(shí)間和精力。
總結(jié)
以上所述是小編給大家介紹的Vue 中使用 typescript的方法詳解,希望對(duì)大家有所幫助!
相關(guān)文章
vue實(shí)現(xiàn)點(diǎn)擊選中,其他的不選中方法
今天小編就為大家分享一篇vue實(shí)現(xiàn)點(diǎn)擊選中,其他的不選中方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09Vue實(shí)現(xiàn)簡(jiǎn)易翻頁(yè)效果源碼分享
本文給大家分享了vue實(shí)現(xiàn)簡(jiǎn)易翻頁(yè)效果,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-11-11Vue router-view和router-link的實(shí)現(xiàn)原理
這篇文章主要介紹了Vue router-view和router-link的實(shí)現(xiàn)原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03vue-router(this.$router)如何在新窗口打開(kāi)路由跳轉(zhuǎn)頁(yè)面
這篇文章主要介紹了vue-router(this.$router)如何在新窗口打開(kāi)路由跳轉(zhuǎn)頁(yè)面問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12vue+iview的菜單與頁(yè)簽的聯(lián)動(dòng)方式
這篇文章主要介紹了vue+iview的菜單與頁(yè)簽的聯(lián)動(dòng)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07vue刪除html內(nèi)容的標(biāo)簽樣式實(shí)例
今天小編就為大家分享一篇vue刪除html內(nèi)容的標(biāo)簽樣式實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09一步步從Vue3.x源碼上理解ref和reactive的區(qū)別
vue3的數(shù)據(jù)雙向綁定,大家都明白是proxy數(shù)據(jù)代理,但是在定義響應(yīng)式數(shù)據(jù)的時(shí)候,有ref和reactive兩種方式,如果判斷該使用什么方式,是大家一直不很清楚地問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于從Vue3.x源碼上理解ref和reactive的區(qū)別的相關(guān)資料,需要的朋友可以參考下2023-02-02安裝VUE-CLI一直失敗的排錯(cuò)過(guò)程及解決方案
這篇文章主要介紹了安裝VUE-CLI一直失敗的排錯(cuò)過(guò)程及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10