1. 程式人生 > 程式設計 >Vue 中使用 typescript的方法詳解

Vue 中使用 typescript的方法詳解

什麼是typescript

typescript 為 javaScript的超集,這意味著它支援所有都JavaScript都語法。它很像JavaScript都強型別版本,除此之外,它還有一些擴充套件的語法,如interface/module等。 typescript 在編譯期會去掉型別和特有語法,生成純粹的JavaScript。

Typescript 5年內的熱度隨時間變化的趨勢,整體呈現一個上升的趨勢。也說明ts越來越️受大家的關注了。

Vue 中使用 typescript的方法詳解

安裝typescript

npm install -g typescript
tsc greeter.ts

舉個栗子

左右對比可以看出typescript 在編譯期會去掉型別和特有語法,生成純粹的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" };

為什麼需要使用它?

優勢:

  1. 靜態型別檢查
  2. IDE 智慧提示
  3. 程式碼重構
  4. 可讀性

1. 靜態型別檢查

靜態型別檢查首要優點就是能儘早的發現邏輯錯誤,而不是上線之後才發現。

1.1 型別分析

傳參過程欄位錯誤,或型別錯誤使用。(進行引數標註後,在編碼過程中即可檢查出錯誤。)

1.2 型別推斷:函式的返回值可通過ts型別推斷得出.這一步驟是 在編譯時進行在編譯時進行型別分析

example: eg1: 我在使用ts寫vue-router 的 動態路徑引數時就發現了一個問題,動態路徑引數 以冒號開頭 path: '/user/:id',我們會誤認為id為一個number,如果使用ts你將得到提示 我們應該傳入一個string型別的id. 傳入一個number型別的id可能並不會出錯,js會對它進行隱式型別轉換,但是傳入一個string會使它更安全和規範.

eg2: 個人使用後的效果

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);

Vue 中使用 typescript的方法詳解

2.智慧補全

在編寫程式碼時ide就會提示函式簽名.

interface Person {
 firstName: string;
 lastName: string;
}
/**
 * 問候語句
 * @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 };

直接將這個ts檔案引入到其他ts檔案中,不僅補全了所有的引數型別,還告訴你需要填入一個引數,並且你只有填入一個Person型別的物件才不會報錯。(智慧補全和引數校驗)

Vue 中使用 typescript的方法詳解

3.在重構上

動態一時爽,重構火葬場.

typescript 在重構上的優勢,我們主要從三方面說明。

  • 重新命名符號,可將一切引用的地方都進行修改。
  • 在vs code 中如果我們想修改函式、變數或者類的名稱,我們可以使用重新命名符號的功能,在當前專案中正確的修改所有的引用.這個既可以在ts中使用,也可以在js中使用,而它的底層實現都是依靠ts 的語法分析器實現的。
  • 自動更新引用路徑(vs code)。
  • 在重構的過程中,我們可能需要移動檔案的路徑,這往往會導致其他地方的import失效,這時候vs code提供了自動更新引用路徑的功能。它的底層實現也是依靠ts 的語法分析器實現的。
  • 校驗函式簽名。

有時候我們會重構類或函式的簽名,如果有引用到的地方忘記修改,除了執行時候能發現,其他時候往往難以察覺,且 ESLint 也只能是排查簡單的問題,所以出了BUG會非常麻煩。 而 TypeScript 不一樣,在編碼時就能及時的發現哪裡錯了,哪裡應該改動但沒有修改。

[函式簽名 MDN][5]

4. 可讀性

可讀性上,TypeScript 明顯佔優,檢視開原始碼時,如果註釋不是很完善,往往會看的雲裡霧裡,而 TypeScript 在同等條件下,至少有個型別,能讓自己更容易明白程式碼的引數、返回值和意圖。

TS+Vue初探

配置

在正式開發之前,我們需要了解一些基本的配置。

1.tsconfig.json 是 ts 專案的編譯選項配置檔案. 在 ts 專案中如果你不新增這份檔案,ts 會使用預設的配置. 掃描二維碼獲取配置專案。

Vue 中使用 typescript的方法詳解

  1. ts-loader:Webpack 的TypeScript 載入器,就是為了讓 webpack 編譯 .ts .tsx檔案。
  2. TSLint:.ts .tsx檔案的程式碼風格檢查工具。(作用類似於ESLint)
  3. vue-shim.d.ts:由於 TypeScript 預設並不支援 *.vue 字尾的檔案,所以在 vue 專案中引入的時候需要建立一個 vue-shim.d.ts 檔案,放在專案根目錄下,例如 src/vue-shim.d.ts。

Vue 中使用 typescript的方法詳解

在Vue裡面寫TS的方式

圖中內容應寫在script中的lang="ts" 。

上圖:使用 Vue.extend的基礎用法。

Vue 中使用 typescript的方法詳解

圖:基於類的Vue元件

Vue 中使用 typescript的方法詳解 通過

對比我們發現,上面的編碼方式更接近我們平時JS的寫法,但是我們並不能感受到ts的型別檢查和型別推斷。下面張圖的寫法更有助於我們得到ts的型別檢查。這需要我們引入 vue-class-component ,雖然template中還是不能得到補全,但是script 中的內容得到了更好的補全。 下面我們瞭解一下vue-class-component的作用。

vue-class-component & vue-property-decorator

vue-class-component 強化 Vue 元件,使用裝飾器語法使 Vue 元件更好的跟TS結合使用。 vue-property-decorator在 vue-class-component 的基礎上增加了更多與 Vue 相關的裝飾器,使Vue元件更好的跟TS結合使用。

這兩者都是離不開裝飾器的,(decorator)裝飾器已在ES提案中。Decorator是裝飾器模式的實踐。裝飾器模式呢,它是繼承關係的一個替代方案。動態地給物件新增額外的職責。在不改變介面的前提下,增強類的效能。下面我們以 鋼鐵俠 為例講解如何使用 ES7 的 decorator。

以鋼鐵俠為例,鋼鐵俠本質是一個人,只是“裝飾”了很多武器方才變得那麼 NB,不過再怎麼裝飾他還是一個人,它本質是沒有被改變的。所以,裝飾器沒有改變其繼承關係,但也同樣能夠為它新增很多厲害的技能。簡單的說,裝飾器是在不修改一個類的繼承關係的前提下,為一個類修改或新增成員。

Vue 中使用 typescript的方法詳解

裝飾器主要接收的三個引數: target 要在其上定義屬性的物件。 key 要定義或修改的屬性的名稱。 descriptor 將被定義或修改的屬性描述符。下面我們通過程式碼中我們為一個人添加了飛行的功能:

Vue 中使用 typescript的方法詳解

typescript VS JavaScript

瞭解了上面的基礎知識,現在我將同一段程式碼分別使用js 和 ts來書寫,現在我們來對比他們之間的差別。

Vue 中使用 typescript的方法詳解

Props (Properties) 使用js,我們有很多中方式來定義元件的 Props,但是大多都摻雜了 Vue 的私有特徵,與 ES 格格不入,例如左邊的程式碼,明明我們是把這個物件的 prop 屬性定義成為了一個包含兩個 string 元素的物件,但是我們卻可以直接通過這個物件來訪問 "name" 欄位,這很明顯是不符合 ES 語義的。再來看看右邊的 TS 選手,通過 Prop 裝飾器把指定的欄位標記為了 Prop,既保留了 ES 語法的語義,而且還能與 Vue 完美的配合,更棒的是,我們可以在編碼的過程中享受 TS 對 Prop 欄位的靜態型別檢查。Method 和 data 再來看看 Method,JS 中定義 method 還是有我們上面提到的那個不符合 ES 語義的毛病。而在 TS 中,method 不需要額外的裝飾器——例項方法就會自動成為 Vue 元件的 method。類似的還有 data ,使用 TS 的語法,例項欄位即可自動成為 Vue 元件的 data。Computed 在傳統的使用 JS 編寫的 Vue 程式碼中,如果要定義計算屬性,我們需要在 computed 屬性中定義相應的函式。而這在 ES 中其實早就已經有了對應語義的語法——getter,所以在使用了 vue-class-component 的 vue 元件中,我們可以直接使用 getter 來定義計算屬性,不管是在語法上還是在語義上,相比普通的 JS 都略勝一籌

總結:我們使用vue-class-component讓vue元件的定義更加符合ES語義,使得TS能夠更好的進行語法分析,並基於此進行型別檢查。

業務場景中使用TS + Vue

1. 在Vue專案中定義data和props

Vue 中使用 typescript的方法詳解

這樣的寫法,讓我產生了兩個疑惑。

1.1 為什麼使用 的寫法 @Prop(Number!:) propA!: number 而不是 @Prop(Number) propA: number

1.2 為什麼Prop需要前後寫兩次型別?

自我自答環節:

答1.1:因為我們定一個Phone這個類,沒有對phone、condition這些欄位通過constructor進行初始化,所以需要在屬性上使用 顯式賦值斷言來幫助型別系統識別型別,這樣能夠讓屬性會被間接地初始化。答1.2:前面括號裡面的型別標註是Vue提供的型別檢查。冒號後面的是為TS提供的型別標註。

2. 編寫一個函式

這裡我們將使用到js的介面,它經常用於定義複雜的引數型別和返回值型別。

Vue 中使用 typescript的方法詳解

上面的例子,我們需要為opts這個引數定義型別,方便後面編碼時的使用,這時我們就需要編寫一個介面來對它進行型別定義。這個接口裡麵包括三個必須屬性和一個可選屬性。必須屬性在物件初始化的時候必須賦值,但是有時候某個物件中的屬性可以被忽略的,不一定會被需要。我們可以將它設定為可選項。

隨著業務的發展,一些引數的欄位會變的越來越多,越來越複雜。可能你想有沒有什麼一勞永逸的方法,讓介面更加簡單,甚至讓它自動的適應業務的變化。於是我想出了這樣的程式碼:

Vue 中使用 typescript的方法詳解

上面的程式碼: 定義了一個鍵為string,他的值為number或string型別的介面,並且該介面的所有欄位都是可選的,你甚至可以傳入一個空物件。所以我們可以使用上面的介面可以代替下面的介面,但是反之不行.

然而我們不應該去繞開這些檢查,因為這樣ts就不會為你檢查使用介面的物件應該存在那些屬性或者方法了。使用ts的意義就被大大減弱了。

3. 編寫第三方依賴

在日常的開發過程中,我們經常會遇到將第三方依賴引入到 TS 專案中沒有型別檢查的問題,這往往是因為這些專案沒有提供型別定義檔案。這個時候,我們可以手動為這些第三方庫編寫型別定義檔案,型別定義檔案在編譯後會被完全忽略,所以並不會對現有程式碼產生影響。以上面這個較為複雜的函式為例,它的作用是將傳入的所有的引數的所有欄位合併到一個新的物件中並返回,儘管他的功能比較簡單,但是為它編寫型別定義還是需要一些 TS 的技巧。

Vue 中使用 typescript的方法詳解

1. 外部模組宣告: 首先我們需要建立一個拓展名為 .d.ts 的檔案,並在其中宣告一個模組,宣告的模組名稱需要跟我們在其他檔案中引入的路徑相同。

Vue 中使用 typescript的方法詳解

2. 型別引數——泛型:首先讓我們考慮最簡單的情況,當傳入一個引數的時候,extend 函式應該返回與引數型別相同的物件,但是我們在編寫函式的時候並不知道使用者會傳入何種型別的引數,所以我們可以定義一個型別引數 T1,這時,extend 就被稱為泛型函式,T1 也被稱做泛型引數。在上面的例子中,extend 函式接受一個型別為 T1 引數並返回一個型別為 T1 的值,T1 需要使用者手動傳入,還好 TS 足夠聰明,在絕大多數情況下,TS 可以根據引數型別來自動推斷型別引數,免去了我們輸入型別引數的繁瑣步驟。只接受一個引數的 extend 函式並沒有很複雜,我們可以繼續考慮一些更復雜的情況。

Vue 中使用 typescript的方法詳解

這次讓我們定義一個接受三個引數的 extend 函式,同時它也接受三個泛型引數,而它返回值型別呢,則是 T1,T2,T3 的交叉型別。交叉型別讓我們可以把現有的多種型別疊加到一起成為一種型別,它包含了所需的所有型別的特性,相當於對這些型別的成員求並集。 例如, T1 & T2 & T3 這個型別的物件同時擁有了這三種類型的成員。在這裡,交叉型別就滿足了我們對 extend 函式返回值型別的要求。值得注意的是,實際的 extend 函式可以接受不定個數的引數,也就是說,我們為它編寫的型別定義也需要同時相容接受不定個數引數的情況,這就需要 TS 提供的函式過載功能。

Vue 中使用 typescript的方法詳解

3. 過載:在大多數靜態型別程式語言中,編譯器允許存在引數型別、個數不同的多個同名函式,這個特性被稱為函式過載。TS 支援函式過載的特性,所以我們可以定義多個接受不同數量引數的 extend 方法,在使用者呼叫時,TS 會自動的在這些同名函式中選擇正確的過載定義。有了函式過載的幫助,我們可以在使用 extend 的大多數場景下享受到型別檢查的好處,只有在引數個數超過4個的時候,TS 才無法推斷出返回值型別。需要注意的是在 JS 中,執行時並不提供函式過載的能力,我們無法定義多個同名函式,即使他們接受的引數數量並不相同,為了實現函式過載的效果,開發人員需要手動在單個函式中對引數的型別、數量做出判斷。

Vue 中使用 typescript的方法詳解

到這裡我們的第三方宣告就完成了,即使一個簡單函式的第三方宣告,我們也運用了很多ts的相關知識。

個人感受

前面我們講解了,使用在vue中使用ts能帶給我們的種種便利,現在就我個人感受而言,說一下美中不足的地方。

1.即使使用了ts,template 部分仍沒有靜態型別檢查和IDE智慧提示,但官方成員表示在以後的 Vue 單檔案中會提供這項功能。 2.將 Vue 單檔案元件引入 TS 檔案中,無法正確的提示其檔案位置。 3.Vue 周邊工具,比如 Vuex,它對ts的支援薄弱,大量的功能難以直接遷移到ts中,並且沒有好的官方支援的方案。 4.毫無疑問,使用 TS 進行開發,相比於 JS ,我們需要花費更多的時間和精力。

總結

以上所述是小編給大家介紹的Vue 中使用 typescript的方法詳解,希望對大家有所幫助!