TypeScript infer 關鍵字
本節要介紹的 infer
關鍵字有些難理解,我們來通過一個類比來幫助理解。
語句 let num
中,通過 let
來聲明了一個變量,那怎樣聲明一個不確定的類型變量呢? 答案是使用 infer
關鍵字,infer R
就是聲明了一個類型變量 R
。
1. 慕課解釋
在條件類型表達式中,可以在 extends
條件語句中使用 infer
關鍵字來聲明一個待推斷的類型變量。
2. 通過 ReturnType 理解 infer
infer 相對比較難理解,我們先看下 TypeScript 一個內置工具類型 ReturnType
。
ReturnType<T>
– 獲取函數返回值類型。
const add = (x:number, y:number) => x + y
type t = ReturnType<typeof add> // type t = number
代碼解釋:
通過 ReturnType 可以得到函數 add() 的返回值類型為 number 類型。但要注意不要濫用這個工具類型,應盡量多的手動標注函數返回值類型。
來看一下 ReturnType 的實現源碼:
/**
* Obtain the return type of a function type
*/
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
infer
的作用是讓 TypeScript
自己推斷,并將推斷的結果存儲到一個類型變量中,infer
只能用于 extends
語句中。
再來看 ReturnType 的實現:如果 T
滿足約束條件 (...args: any) => any
,并且能夠賦值給 (...args: any) => infer R
,則返回類型為 R
,否則為 any 類型。
繼續看幾個例子:
type T0 = ReturnType<() => string> // string
type T1 = ReturnType<(s: string) => void> // void
type T2 = ReturnType<<T>() => T> // unknown
代碼解釋:
分別可以得到 type T0 = string
type T1 = void
type T2 = unknown
,只要滿足約束條件 (...args: any) => any
,TypeScript 推斷出函數的返回值,并借助 infer
關鍵字將其儲存在類型變量 R
中,那么最終得到返回類型 R
。
3. 借助 infer 實現元組轉聯合類型
借助 infer 可以實現元組轉聯合類型,如:[string, number] -> string | number
type Flatten<T> = T extends Array<infer U> ? U : never
type T0 = [string, number]
type T1 = Flatten<T0> // string | number
代碼解釋:
第 1 行,如果泛型參數 T
滿足約束條件 Array<infer U>
,那么就返回這個類型變量 U
。
第 3 行,元組類型在一定條件下,是可以賦值給數組類型,滿足條件:
type TypeTuple = [string, number]
type TypeArray = Array<string | number>
type B0 = TypeTuple extends TypeArray ? true : false // true
第 4 行,就可以得到 type T1 = string | number
。
4. 小結
infer 理解起來比較抽象,一定要親手寫一下本節中的例子。借助條件類型的 infer
關鍵字來推斷類型,可以實現一些比如聯合類型轉交叉類型、聯合類型轉元組的操作,有興趣的可以了解一下。