一文學會 TypeScript 的 82% 常用知識點(下)

都已經 9021 年了,TypeScript(以下簡稱 TS)作爲前端工程師不得不學的技能,我們必須掌握。

在上篇「一文學會 TypeScript 的 82% 常用知識點(上)」中,主要介紹了 TS 的基本類型,引用類型、類型斷言、接口等基礎知識點。本篇對剩下對內容進行討論,包括:類、函數、泛型

如果 TS 的基礎薄弱,建議先閱讀上篇,大概二十分鐘即可入門。

五、類

類在上篇有所提及,這裏作進一步瞭解。

類的典型結構

包括屬性、方法、構造函數。使用關鍵字 new 創建類的實例。

5.1 類的繼承

使用關鍵字 extends 定義類的繼承。

5.2 類的成員修飾符

5.2.1 public

類的成員修飾符默認是 public,也可以顯式聲明。

上述代碼中,屬性 a 和 b 均被聲明爲公共的。

5.2.2 private

將類的成員聲明爲私有的,即只有類內部訪問。

TS 是結構性類型系統(鴨式辨形),如果兩種類型的結構相同,一般情況下,TS 會認爲它們是兼容的。

可是,當類的成員帶有 private 或 protected 修飾符時,情況卻不一樣。

上述代碼中,雖然看上去它們的結構相同。但是,當一個類的成員中存在 private 或 protected 時,如果需要另一個類與它兼容,則需要兩個類的聲明來源於同一份聲明,例如通過繼承。

5.2.3 protected

修飾符 protected 和 private 類似,區別在於使用 protected 修飾的成員,在派生類可以訪問。

5.2.4 readonly

修飾符 readonly 將屬性設置爲只讀。

將屬性設置爲只讀,只能在初始化時候定義其值,定義後不能修改。

5.2.5 static

在類類型中,我們區分了類的靜態部分和類的實例部分。修飾符 static 將類成員聲明爲靜態成員。

5.2.6 抽象類

我們創建基類時,如果不希望基類能被實例化,可以使用 protected 修飾符。

更普遍的做法是,使用 abstract 修飾符。abstract 能定義抽象類和抽象類中的抽象方法。

5.2.7 getter 和 setter

很多時候,對某個屬性讀取時,同時需要對其進行處理,例如。

更加簡單的辦法是,通過 存儲器 處理。

getter 和 setter 統稱存取器,其實在 ES5 就已經存在,很多朋友沒有留意。如果對存取器不熟悉的,也可以通過 TS 來理解。

六、函數

在 TS 中,有幾種方式定義函數類型。

6.1 函數簽名

利用上文提到的函數簽名來定義函數類型。

6.2 完整的函數類型

除了使用函數簽名外,還可以直接對函數進行類型描述。

但是,這種方式毫無疑問是太繁瑣了,TS 存在類型推斷的功能,它能根據等號一側已存在的函數類型,而推斷出另一側的函數類型,從而簡化代碼。

6.3 類型推斷

函數推斷簡化代碼

6.4 可選參數

在 JS 中,參數都是可選的,如果函數聲明瞭參數,但是實際沒有傳參,則參數值是 undefined。

默認情況下, TS 要求參數是必須的,函數聲明瞭參數,就應該傳進對應的參數。

但確實存在某個參數可能存在,可能不存在的情況。這時候就需要用到可選參數了。

值得注意的是,可選參數必須跟在必須參數之後。

6.5 默認參數

在 ES6 中,可以給參數設定默認值。

而在 TS 中,默認參數的特性也是和 ES6 一致,而默認參數的類型是:默認值和 undefined 的聯合類型。

6.6 剩餘參數

在 ES6 中,引入了剩餘參數,代表由剩餘所有參數組成的參數數組。

在 TS 中給剩餘參數添加類型,和普通參數接近,區別在於剩餘參數肯定是數組類型。

6.7 函數重載

函數根據傳入不同的參數而返回不同的數據,這是十分普遍的情況。

如何對這種情況進行類型描述呢?有些朋友可能會想到使用聯合類型進行處理。

但是,這樣不能很好地描述輸入和輸出類型的關係。

在上述例子中,參數和返回存在對應關係:參數是 number 類型,則返回 boolean,參數是 boolean 類型,則返回 number,其他則返回 undefined。

此時,我們可以運用函數重載描述這些對應關係:

上述代碼中,定義了三個 foo 函數的重載,需要注意兩點。

  1. 具體的函數聲明不屬於重載部分,即 function foo(a: any): any 並不是重載,而是具體的函數聲明,所以例子中只有三個函數重載;

  2. 當匹配重載列表時候,是根據定義時候的順序由上到下匹配的。在例子中,傳入參數是 undefined 時,首先嚐試匹配 number,然後嘗試匹配 boolean,最後嘗試匹配 any,匹配成功則使用 any 這個重載定義。

7 泛型

泛型其實並不高深,藉助幾個已知概念可以幫助理解。

7.1 泛型函數

上文提到,當函數的參數和返回的類型存在聯繫時,我們使用了函數重載進行類型描述。

假如希望函數的參數和返回的值,它們之間的類型一致。如果使用函數重載,則需要:

這顯得十分繁瑣。而且,當傳入的參數是數組或其他對象時,匹配的是函數重載的 object 部分,返回值的類型也是 object,丟失了原有的結構。

我們期望即使傳入複雜的結構對象,也保留它們的類型描述。像上述代碼中,傳入是 number[] 類型的參數,期望返回的也是 number[] 類型描述,而不是 object 類型描述。

而使用泛型就能解決這個問題。以下藉助變量的概念來對泛型進行解釋。

變量我們都清楚,當變量被賦值成某值或對象時,該變量就代表着某值或對象。

而在類型系統中,通過引入類型變量,達到和變量相同的效果:當類型變量被賦值成某類型,則類型變量就代表該類型。

上述代碼中,在函數名後添加 <T>, 代表在類型系統中聲明瞭類型變量 T。所以,在對參數 a 和返回值進行類型描述時,我們可以使用 T 這個類型變量。

另外,上述代碼使用字母 T 代表類型變量,並不是固定的,也可以使用字母 A、a 等合法的變量名。只不過約定俗成,T 代表着 Type(類型),這樣其他人閱讀代碼也一目瞭然。

既然是變量,我們怎麼給這個類型變量傳參呢?

可以清晰地看到,在調用函數時,使用尖括號傳入具體的類型值。以 foo<number[]>([1, 2, 3) 爲例,相當於應用 function<number[]>(a: number[]): number[] 類型校驗。這樣,在參數和返回值中都保留了明確的數據結構。

上文我們提到類型推斷,同樣在泛型中也可以應用。

上述代碼中,省略了明確的類型傳參,但 TS 會根據我們傳入的參數的類型,自動確定 T 的類型。

7.2 泛型接口

我們知道,接口是具有函數簽名的,形如:

接口中的函數簽名也存在泛型的形式:

另外,還可以將泛型參數作爲接口的參數:

7.3 泛型類

泛型類和泛型接口類似,聲明泛型參數後,在類中就可以使用。

結語

以上就是關於 TS 的關鍵知識點,熟悉上下兩篇文章的內容,即可閱讀和使用大部分的 TS 代碼。

TS 的學習要點不多,一個週末時間基本能搞明白。

學習 TS 的資料主要是官網,特別是 TS handbook,本文大部分內容也是基於其整理的,希望能給大家帶來一些幫助。

本文轉自頭條號:前端專欄

文章鏈接:https://www.toutiao.com/i6762435693017825800/?group_id=6762435693017825800

專注分享當下最實用的前端技術。關注前端達人,與達人一起學習進步!

長按關注"前端達人"

發佈了75 篇原創文章 · 獲贊 529 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章