[轉]TypeScript類型編程中的extends和infer示例解析

轉自; https://www.jb51.net/javascript/294261vgi.htm

 

TypeScript類型編程中的extends和infer示例解析

 

引文

在剛接觸TypeScript的時候,使用最多的就是type和interface這兩個關鍵字,用來聲明類型,其實這樣也基本滿足日常需求。但是如果需要設計一些高級類型的話,那麼僅僅用原來所掌握的TypeScript知識是無法滿足需求的。

設計高級類型的話涉及到類型編程的知識點,而類型編程中有兩個關鍵字非常重要,分別是extends和infer。

extends用來約束入參的類型以及進行條件判斷,infer用來聲明局部的類型變量。

extends

條件判斷

我們舉個簡單的例子來說明

1
type isOne<T extends number> = T extends 1 ? true : false

 

我們單獨看T extends 1 ? true : false這部分,這裏和JavaScript中的三元表達式並無二致,但是有些同學不清楚其中extends表示的是什麼含義。

T extends 1 ? true : false表示的含義其實就是傳入的T類型是否能夠賦值給字面量1這個類型,如果可以的話,就返回true,否則返回false

約束參數類型

繼續使用上面的例子,我們單獨看T extends number,這裏extends的意思就是限制傳入的T類型必須是number類型,否則報錯。

爲什麼需要有這個限制?

因爲我們是要判斷類型T是否能夠賦值給字面量類型1,但是如果傳入的參數都不是number類型,那麼就沒必要做後續的條件判斷了。

約束infer推導的局部變量類型

1
2
3
4
type GetFirst<T extends string[]> = T extends [infer FirstChar, ...infer Rest]
  ? `${FirstChar}`
  : never;
type Res = GetFirst<['1', '2', '3']>;

 

來看看報錯信息,我們傳入的參數類型限制爲sting類型的數組,但是infer推導出來的類型實際上是unknown類型,所以導致類型不匹配。

解決辦法有三種:

對FirstChar使用extends先做過濾

1
2
3
4
5
type GetFirst<T extends string[]> = T extends [infer FirstChar, ...infer Rest]
? FirstChar extends string
  ? `${FirstChar}`
  : never
: never;

 

FirstChar和string進行交叉運算

1
2
3
type GetFirst<T extends string[]> = T extends [infer FirstChar, ...infer Rest]
? `${FirstChar & string}`
: never;

 

使用infer extends做類型轉換

1
2
3
4
5
6
type GetFirst<T extends string[]> = T extends [
infer FirstChar extends string,
...infer Rest
]
? `${FirstChar}`
: never;

 

infer extends是在ts 4.7版本支持,低於這個版本無法使用。

類型轉換

1
2
3
4
type StrToNum<T extends string> = T extends `${infer Num extends number}` ? Num : T
type Res = StrToNum<"1">
// ts 4.7時,返回的結果是type Res = number
// ts 4.8及以上, 返回的結果是type Res = 1

 

infer

還是拿例子來進行講解,下面的例子是要提取Promise包裹的類型。

1
2
type PromiseValue<T extends Promise<unknown>> = T extends Promise<infer Value> ? Value : never
type Res = PromiseValue<Promise<string>> // string

 

畫個簡單的圖來描述下如何提取變量類型。

 注意:infer聲明的局部變量,只能在條件語句爲true的分支裏面使用。

如果在false分之裏面使用通過infer聲明的局部變量,編譯器會直接報錯表示找不到這個變量。

組合使用

ReturnType

內置工具類型RetureType用於獲取函數的返回值類型。

1
2
3
4
5
type MyReturnType<T extends (...args: any) => any>
    = T extends (...args: any) => infer R
        ? R
        : any;
type Res = MyReturnType<() => string> // type Res = string

 

Parameters

內置工具類型Parameters用於獲取函數的參數類型。

1
2
3
4
5
type MyParameters<T extends (...args: any) => any>
    = T extends (...args: infer P) => any
        ? P
        : never;
type Res = MyParameters<(a: string, b: number) => void>  // type Res = [a: string, b: number]

 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章