對於前端從業者來講,TypeScript(如下簡稱 TS)已經不算是新技術。前端
Vue3 的源碼基於 TS 編寫, Angular 項目默認支持 TS 等。它出現的頻率愈來愈高,而學習難度並不大,大概一個週末能夠熟悉。數組
投入少,產出大,因此最好仍是花點時間學習一下。函數
本文根據 TS handbook 整理出 TS 關鍵的知識點,並對某些部分做了擴展,但願能幫助你們學習理解。學習
前言
在學習 TS 以前,須要理解它的兩個特色:prototype
- TS 是 JS 的超集
- TS 給 JS 帶來類型系統
這意味着 TS 的根基是 JS,是在 JS 的 基礎上添加了類型系統。3d
類型聲明對象
類型系統的一個特色是使用類型聲明。blog
觀察上述代碼,在 JS 中,使用「等號=」給變量賦值。繼承
通過 TS 的擴展,可使用「冒號:」給變量賦類型。代碼中聲明變量 foo 的類型是 string。索引
類型校驗
類型系統的另外一個特色是進行類型校驗。
在 TS 中,須要校驗「等號=」左右的類型是否匹配。
如上述代碼所示,值存在明確的類型,TS 會校驗左右兩側的類型是否匹配,若不匹配則提示錯誤。
在瞭解這些前置知識後,來看看具體的 TS 知識點。
1、基本類型
繼承 JS 的基本類型如:string、number、boolean、undefined、null。擴展了其餘基本類型如:any、never、void。
1.1 string
表示類型爲字符串
1.2 number
表示類型爲數字
1.3 boolean
表示類型爲布爾類型
1.4 undefined
表示類型爲 undefined
1.5 null
表示類型爲 null
1.6 void
表示類型爲 undefined 或 null。
1.6.1 對於變量
一個聲明爲 void 類型的變量,只能被賦值爲 undefined 或 null。這種應用場景較少。
1.6.2 對於函數
void 用於表示函數沒有返回值,只是執行某些操做。這是 void 的廣泛應用場景。
一個沒有顯式返回的函數,默認 return undefined。符合 void 類型只能被賦值爲 undefined 或 null。
1.7 never
表示永遠不存在值。
典型例子:一個只會拋出異常的函數,它的返回值並不存在。
執行函數則拋出錯誤,連 undefined 都不會返回。
1.8 any
表示可能爲任何類型。
典型例子:不肯定變量的類型或類型是動態的。
2、引用類型
TS 中的引用類型,除了 JS 中的數組類型、對象類型,還擴展了枚舉類型,元祖類型。
2.1 數組類型
表示由某(些)類型組成的數組。有兩種寫法:方括號表示法和尖括號表示法。
2.1.1 方括號表示法
表示 arr 的類型是由數字組成的數組。
2.1.2 尖括號表示法
使用 Array<元素類型>,這是數組泛型的使用形式,關於泛型後續會展開。
2.2 只讀數組
使用 ReadonlyArray<屬性類型> 定義只讀數組。只讀數組只能在數組初始化時定義其值,建立後不能進行修改。
只讀數組和常規數組類型 Array<T> 相似。區別在於:常規數組存在修改數組的方法,只讀數組不存在修改數組的方法。
2.3 object
表示類型爲對象。除了 string、number、bigint、boolean、 undefined、null、symbol 基本類型外的引用類型。
2.4 元組
由定長數組構成,數組中的元素是某(些)類型。
2.5 枚舉
使用關鍵字 enum 定義枚舉類型。默認枚舉值從 0 開始,能夠手動賦值。
3、類型斷言
明確告訴 TS 某個值的類型。有兩種寫法:尖括號寫法、as 寫法。
尖括號寫法
as 寫法
注意事項
類型斷言和類型轉換是有明確區別,不能將它理解成類型轉換。
在闡述此注意事項以前,先引入另外一個概念:聯合類型。
在上述代碼中,string | number 表示的就是一個聯合類型,意味着 answer 的類型能夠爲 string 或 number。
下面逐步解釋類型斷言和類型轉換之間的區別。
上述代碼中,string | number 聯合類型包含 string 類型,因此這兩種類型之間存在聯繫。使用 as 將聯合類型斷言成更加具體的 string 類型。
上述代碼中,將 number 類型斷言爲 string | number 類型。一樣是由於兩種類型之間存在聯繫,因此也容許斷言。至關於將一個具體的 number 類型斷言成更加普遍的聯合類型。
而將 string 類型斷言爲 number 類型,這是兩種不一樣的類型,沒有任何聯繫,斷言會提示錯誤。
觀察上述三個例子,斷言發生在兩種類型存在聯繫的狀況,它並非將一種類型轉換成另外一種類型。
有些腦瓜子靈活的朋友會想到,藉助兩次斷言來進行相似的類型轉換。
這是欺騙了 TS 校驗,後果只能本身承擔。
4、接口
上面提到使用 object 描述對象類型。可是,對於具備複雜結構的對象、函數。上述的 object 類型力有不逮。
上述代碼中,即便是空對象,也能經過 object 類型校驗,而不會校驗對象的結構是否能知足後續使用。
此時,就須要使用接口。在 TS 中,接口是描述值的結構。
上述代碼中,就定義了一個接口來描述參數 o,要求它是一個對象,含有 name 屬性,且屬性值是字符串。
因此,不符合此結構的空對象 {} 就提示錯誤。
通常來講,使用關鍵字 interface 來定義接口。
重寫上述接口 ——
4.1 固定屬性
在接口中,使用 屬性名:屬性類型 的結構定義固定屬性。
如上述代碼所示,傳入的對象須要具備 name 和 age 兩個屬性,不然會報錯。
4.2 可選屬性
在接口中,使用 屬性名?:屬性類型 的結構定義可選屬性。顧名思義,可選屬性能夠存在,也能夠不存在。
4.3 只讀屬性
在接口中,使用 readonly 屬性名:屬性類型 的結構定義只讀屬性。只讀屬性只能在屬性初始化時定義其值,定義後不能進行修改。
4.4 額外檢查
TS 會對對象字面量進行額外的屬性檢查。
在上述代碼中,接口 Point 定義了兩個可選屬性,對象字面量中屬性 x 和接口兼容,屬性 z 是多餘無心義的。
雖然實際的屬性比接口定義的多,按照常規理解,這是能夠經過類型校驗,但事實卻相反。
TS 對於對象字面量是會進行額外的屬性檢查,體如今:
當對象字面量賦值給變量或它直接做爲參數傳遞給函數時,若是對象字面量的屬性沒有在接口中定義,則會報錯。
換句話說,對於對象字面量,當它直接賦值給變量和函數參數時,它的屬性不能比接口描述的多。
這裏重點是直接賦值,若是像例子中,先將對象字面量賦值給變量,再經過變量傳參,這樣間接的方法能夠繞過額外的檢查。
4.5 可索引類型
可索引類型包括字符串索引類型與數字索引類型。
4.5.1 字符串索引類型
字符串索引類型具備字符串索引簽名。
4.5.2 數字索引類型
數字索引類型具備數字索引簽名
4.5.3 混合索引簽名
屬性和索引簽名能夠造成混合索引簽名,可是屬性須要和索引簽名類型匹配。
另外,TS 容許同時使用上述兩種簽名,可是數字索引返回值的類型,它必須是字符串索引返回值類型的子類型。
由於對於 JS 來講,當使用數字索引時,會將它轉換成字符串進行索引。因此它們須要保持一致。
上述代碼中,ThreeD 是 TwoD 的子類型,因此接口 PointA 正確。
4.5.4 只讀索引簽名
能夠將索引簽名設置爲只讀,只能在數組初始化時定義其值,建立後不能進行修改。
4.6 函數類型
函數類型具備調用簽名。
如上述代碼所示,調用簽名包括參數列表和返回值類型。
對於函數類型來講,它校驗的值固然是函數 ——
如上述代碼所示,函數的參數名能夠與簽名的參數名不一樣。關鍵是對應位置的參數類型須要相同。
4.7 類類型
這裏的概念有些複雜,若是有良好的 JS 基礎,會較易理解。
類的關鍵字是 Class,由 ES6 開始引入,並逐步完善。本質上 Class 屬於語法糖,是基於 prototype 原型鏈實現的。
而不管是 ES5 或 ES6,屬性 age 是在建立的實例上,而方法 getAge() 是在實例的原型鏈上。
而類自己,它是不存在 age 屬性 和 getAge() 方法的。
固然,咱們也能夠給類自己定義屬性和方法。 但給類自己定義的屬性和方法並不能經過實例直接訪問。
因此,類與實例的屬性和方法是割裂的。
TS 將描述類的屬性和方法部分稱爲類的靜態部分類型,將描述實例的屬性和方法部分稱爲類的實例部分類型。
在上述代碼中,使用關鍵字 implements 描述類實現了接口。更準確的是:描述 類的實例部分 實現了接口。
實現該接口的類的實例,它是具備 age 屬性,getAge() 方法。而類自己(即類的靜態部分)具備何種屬性與方法,上述代碼沒有進行定義。
因此,這裏所說的類類型,其實是類(實例的)類型。
關於如何定義類的靜態部分的類型,在後續會詳細介紹。
4.8 接口繼承
接口的可使用關鍵字 extends 定義繼承。一個接口能夠繼承多個接口。
4.9 混合類型
一個對象可能混合多種類型。
例如定義一個帶版本號的函數——
值得注意,上述使用類型斷言,將函數斷言爲 Fn,即便 fn 在建立時並不存在 version 屬性。
4.10 接口繼承類
當接口繼承類類型時候,表如今繼承類的成員和結構,但不包括其實現。
接口繼承類的一個場景是,定義一個子類的類類型。
結語
因爲文章篇幅問題,全文拆分紅上下兩篇發佈。
本篇主要介紹了 TS 的基本類型,引用類型、類型斷言、接口等知識點,瞭解上述的知識點能夠閱讀部分 TS 代碼。
下篇涉及函數、類、泛型等稍微複雜的知識點。