infer 的作用是:
在條件型別中,讓 TypeScript 推導出某個型別的一部分,並給它一個名稱。
可以想像成 TypeScript 正在對你說:「你給我一個型別,我來比對一下是不是某個模式。如果是,那我就從裡面幫你推測出某個子型別。」
ts
type Box<T> = { value: T }
// 我要寫一個型別工具,幫我把 T 拿出來
type Unbox<T> = T extends Box<infer U> ? U : never接著帶入:
ts
type A = Unbox<Box<string>> // A 是什麼?我們把 Box<string> 套進 Unbox<T>:
- T 是
Box<string> - 套進
T extends Box<infer U>→ 成立,因為型別對得起來 - 所以 infer U 這裡就等於 string
- 整個結果就會回傳 U,也就是 string
反之如果這邊傳進去的不是 Box<T> 的話,就會回傳 never。
換個實例
先來定義函式型別:
ts
type Fn = (a: number, b: string) => boolean再來寫一個型別工具,把回傳值 boolean 拿出來:
ts
type Return<T> = T extends (...args: any[]) => infer R ? R : never這代表如果 T 是「某種函式」,我就把它的「回傳型別」抓出來叫做 R。
ts
type A = Return<Fn> // A 是 booleaninfer 只能用在條件型別中
正確用法必須在 extends ... ? ... : ... 條件型別裡面才行。
ts
type Wrong = infer T // ❌ 不能這樣寫infer 不只能用一次,也可以用多次!
可以在同一個型別裡用多個 infer,推導多個參數型別。
ts
type ExtractParams<T> = T extends (a: infer A, b: infer B) => any ? [A, B] : never
type Fn = (id: number, name: string) => boolean
type Params = ExtractParams<Fn> // [number, string]