成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

類型體操:探究 TypeScript 內置高級類型

開發 前端
TypeScript 的類型系統,最基本的是簡單對應 JavaScript 的 基本類型,比如 string、number、boolean 等,然后是新增的 tuple、enum、復合類型、交叉類型、索引類型等 增強類型。

大家好,我是前端西瓜哥,今天來做做 TS 類型體操。

TypeScript 類型編程

TypeScript 的類型系統,最基本的是簡單對應 JavaScript 的 基本類型,比如 string、number、boolean 等,然后是新增的 tuple、enum、復合類型、交叉類型、索引類型等 增強類型。

這里會有一個問題,就是函數聲明支持不同類型的重復編寫問題,比如我的一個函數要接收一個數組,然后從中取中一個元素。

一旦我們傳入的數組類型不同,都要寫多一個 type 別名,未免太繁瑣。

type getStrItem = (items: string[]) => string;
type getNumItem = (items: number[]) => number;
// ... 每增加一種類型都要寫多了一個 type 別名
const getStrFirst: getStrItem = (a) => {
return a[0];
}

為解決這個問題,TypeScript 引入了 泛型,讓類型也能成為參數了。

type getItem<T> = (items: T[]) => T
const getStrFirst: getItem<string> = (a) => {
return a[0];
}

上面的 T 就是一個類型參數,當我們通過 類型別名<具體類型>? 形式(上面代碼對應 getItem<string>),我們就能得到一個具體的類型了。

鑒于 JavaScript 太靈活,TypeScript 實現的是結構類型系統,我們又覺得泛型的簡單推到 T 的粒度還是不夠細,我們希望能夠獲取 T 內部的結構。

于是,TypeScript 在泛型的基礎上,又提供了 類型編程,通過一些語法,我們可以拿到 T 下更細粒度的類型,或通過判斷拿到其他類型。

這個也被大家戲稱為 類型體操。可能是因為實現起來花里胡哨像是在參加體操大賽的原因。

總結一下,從類型能力上的增強的過程來說,就是:

基本類型 -> 泛型 -> 類型編程(類型體操)

TypeScript 內置高級類型

TS 代碼版本為 4.8.2

下面我們來看一下 TypeScript 內置的幾個高級類型,它們用了類型編程。

Pick<Type, Keys>

Pick 的作用是,從 T 類型(對象類型)中,提取出 K(聯合類型)圈定的 key,返回一個新的對象類型。

圖片

這里我們通過 Pick 提取了需要的 pos 和 radius 物理信息屬性。

看看 Pick 的實現:

/**
* From T, pick a set of properties whose keys are in the union K
*/
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};

首先我們看等號左側的 ??<T, K extends keyof T>??,類型參數有兩個,T 和 K。

先說類型參數命名。

類型變量命名和寫 JS 變量一樣,隨意起名。但建議首字母大寫,以防止和一些關鍵字混淆(比如 extends, as, infer),這些關鍵詞都是小寫的。

T 通常代表一個要被分析的類型(Type),K 通常代表對象屬性名(Key)。就像數學中函數的 x 和 y 一樣,想不到好的命名就用這倆。

keyof 是類型運算符,用于提取對象的屬性(key),然后拼裝成聯合類型。?

圖片

?extends 用于限制類型參數的范圍。比如 <T extends string> 表示 T 類型必須是 string 的子類,像字面量的 "a" 或 string 都是 string 的子類。如果不是 string 子類,編譯無法通過。

還有一種是 extends ? : 的類似 JS 中三元運算符的語法,它在等號的右側,用于實現條件判斷。它和前面提到的 extends 不是同一樣東西,后面我會說到。

Ok,我們整體看看 <T, K extends keyof T> 代表什么意思。它表示傳入 T 和 K 兩個類型參數,然后 K 必須是 T 的屬性組成的聯合類型中的一部分。

我們再看看等號右邊 { [P in K]: T[P]; };,它是對類型進行 重映射。

in 用于對聯合類型進行遍歷。也就是遍歷我們需要用到的 key,作為索引 P,然后它的值還是用對應的 T[P]。

Exclude<UnionType, ExcludedMembers>

Exclude 的作用是,從聯合類型中剔除掉一些類型。

實現如下:

/**
* Exclude from T those types that are assignable to U
*/
type Exclude<T, U> = T extends U ? never : T;

這里涉及到一個經常用到的 條件語法:extends ? :?,你可以把它類比為 JS 中的三元表達式(即 condition ? a : b)。

為了更好的講解,我們實現一個類型 IsNumber,判斷一個類型是否為數值類型。

type IsNumber<T> = T extends number ? true : false;
// 使用
type A = IsNumber<1> // true
type B = IsNumber<"str"> // false

T extends number 判斷 T 是否為 number 的子類,如果是的話,返回 true,否則返回 false。

需注意和前面的類型參數上 extends 是完全不同的東西。

回到我們的 Exclude,邏輯就很清楚了,就是判斷 T 是否為 U 的子類,如果是的話,返回 never(效果是被丟棄);否則返回 T。

圖片

?你是不是有點奇怪結果,邏輯看起來不應該是 "a" | "b" | "c" 不是 "b" 的子類,返回 "a" | "b" | "c" 嗎?怎么編程了 "a" | "c"?

其實這是聯合類型的特殊邏輯,如果聯合類型使用了 extends,它就會被打散,變成多個獨立的類型進行判斷,最后再組合起來。

所以真正邏輯是, "a" | "b" | "c" 被打散,變成依次判斷 "a" 、"b"、"c" 是否為 "b" 的子類,分別得到  "a" 、never、"c",然后聯合起來,就變成了  "a" | "c"。

ReturnType<Type>

獲取函數類型的返回值類型。

圖片

實現為:

/**
* Obtain the return type of a function type
*/
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

等號左側的 (...args: any) => any 代表一個任意函數類型,用于限制傳入參數的類型。

然后我們看到了一個新的關鍵詞 infer,代表引用的意思,用于類型推導。

extends 和 infer 搭配,可以實現 模式匹配,如果 extends 匹配成功,infer 就能推導獲得對應的類型。

如果你了解  JS 的正則表達式,你會發現它們很像,infer 好比是捕獲組。

'ABC'.replace(/A(.)C/, '$1') 
// 'B'。提取了模式上匹配的一個字符串

在 T extends (...args: any) => infer R ? R : any; 中,我們給返回值部分設置了 infer,并提供了一個局部變量 R。

如果 extends 條件判斷是繼承關系,那么變量 R 就會被賦值函數的返回值。

后面的判斷為真的分支(? 后面的表達式)就能拿到這個 R。判斷為假的分支就無法拿到,因為匹配失敗了。

這個 extends + infer 其實就是類型體操的精髓,可以在傳入類型 T 繼續拆分,拿到更細粒度的類型。

更多類型體操學習

還有更多的類型編程的技巧因為篇幅原因就不說了,比如還有:

  • as 運算符可以做類型索引的重映射。
  • 通過數組的 "length" 可以實現數字運算。
  • 通過遞歸實現循環邏輯。
  • 一些特殊的類型()的處理等。

TypeScript 的類型是圖靈完備的,可以實現各種判斷、循環、加減的邏輯。當然某些邏輯實現起來很繁瑣就是了。

它的語法也是與眾不同:它做了 “壓縮”。一個類型的編程只是一個表達式,需要用 extend ? : 的方式不停嵌套實現邏輯。TS 類型體操學起來,某種意義上確實有點像學一門新的語言,而且有那么一點古怪。

我曾懷揣著成為類型體操運動員,去看官方文檔,發現文檔很細碎,而且也是英文,學起來磕磕絆絆,很快就放棄了。

心里不禁嘀咕:類型體操好難學啊,一團亂麻。

我就想,有沒有什么優秀的關于類型體操的課程呢?

直到最近我發現了,掘金推出的課程:《TypeScript 類型體操通關秘籍》,也不算新課了,但寫得確實好。

這是我覺得類型體操寫得最好的課程,共 24 節,只需要 29.9。

這性價比可太高了,這課程要是我出的,要是這質量我可得賣 99.9。

責任編輯:姜華 來源: 前端西瓜哥
相關推薦

2021-12-10 08:21:15

TypeScript高級類型類型體操

2025-04-10 05:00:00

JavaScriptReactWeb

2022-03-09 20:18:49

TypeScript類型函數

2022-02-12 22:16:53

TypeScript類型字符串

2020-12-29 07:15:34

TypeScript語言代碼

2022-02-09 08:11:50

架構

2020-09-15 08:35:57

TypeScript JavaScript類型

2022-08-10 09:03:35

TypeScript前端

2024-02-19 10:24:32

Chainable工具類型類型體操

2024-03-04 06:40:49

工具類型TypeScripDeepPick

2021-08-24 13:05:25

TypeScript代碼前端

2025-02-14 08:26:47

TypeScripDeepSeek

2021-07-27 06:06:34

TypeScript語言運算符

2022-05-04 09:02:41

TypeScript類型工具

2022-02-25 09:06:02

TypeScripnever工具

2022-09-05 17:09:55

SQL Server數據庫

2010-10-08 09:02:03

JavaScript基

2022-01-19 23:41:56

TS索引類型

2021-06-09 07:55:19

Typescript類型檢查

2022-08-08 09:00:42

TypeScript映射類型
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲一区二区免费视频 | 亚洲精品久久久久久久久久久久久 | 精品久久一区二区三区 | 国产精产国品一二三产区视频 | 国产精品久久久久久久久久了 | 亚洲国产一区在线 | 自拍偷拍一区二区三区 | www.久| 亚洲精品一区二区三区在线观看 | av黄色在线观看 | 精品美女久久久 | 国产精品69久久久久水密桃 | 国产91在线 | 中日 | 天天干视频| 最新av中文字幕 | 亚洲性在线 | 九九久久免费视频 | 国产欧美日韩一区二区三区 | www.天天操.com| 欧美日韩视频一区二区 | 午夜99| 成人h视频在线观看 | 国产精品视频久久 | 亚洲视频中文字幕 | 男人的天堂在线视频 | 午夜寂寞影院在线观看 | 国产在线观看一区二区三区 | 欧美中文在线 | 欧美日韩国产一区二区 | 四虎影音 | 成年人在线 | 一级片在线观看视频 | 日韩精品亚洲专区在线观看 | 啪啪毛片| 性色的免费视频 | 中文字幕一区二区三区精彩视频 | 精品免费国产视频 | 久久国产精品-久久精品 | 9999精品视频 | 美女视频网站久久 | 免费看a |