1 什麼是「infer」
1.1 概念
infer 只能在 條件類型(conditional types) 中使用,用來 在類型推斷時聲明一個待推斷的類型變量。
語法為:
T extends SomeType<infer U> ? U : never
可以這麼理解:
- 如果
T能匹配SomeType<某個類型>的結構 - 那麼把內部類型推斷為
U - 然後返回
U
1.2 特點
1.2.1 只能在 extends ? : 中使用
不能單獨寫,比如下邊這麼寫就是錯的:
type A = infer T;
1.2.2 右側的類型結構必須能匹配
type A<T> = T extends [infer U] ? U : never;
type B = A<[string]>; // string
type C = A<string>; // never
2 基本用法
2.1 提取函數返回值類型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type A = ReturnType<() => number>;
// A = number
infer R 就是 推斷函數的返回值類型。
2.2 提取參數類型
type FirstArg<T> = T extends (arg: infer P, ...args: any[]) => any ? P : never;
type A = FirstArg<(x: string, y: number) => void>;
// A = string
2.3 提取數組元素類型
type ElementOf<T> = T extends (infer U)[] ? U : never;
type A = ElementOf<string[]>;
// A = string
2.4 提取 tuple 的某個元素
type First<T> = T extends [infer F, ...any[]] ? F : never;
type A = First<[string, number, boolean]>;
// A = string
在這個例子中,我們提取的是 tuple 的第一個元素。
2.5 提取對象中某個 key 的類型
type PropType<T, K extends keyof T> =
T extends { [Key in K]: infer R }
? R
: never;
type A = PropType<{name: string; age: number}, 'age'>;
// A = number
2.6 對象路徑提取
type Path<T> = {
[K in keyof T]:
T[K] extends object
? `${string & K}.${Path<T[K]>}`
: `${string & K}`;
}[keyof T];
假設説我們有這麼一個類型:
type User = {
id: number;
name: {
first: string;
last: string;
};
address: {
city: string;
location: {
lat: number;
lng: number;
};
};
};
執行 Path:
type UserPath = Path<User>;
之後得到的結果展開就是:
type UserPath =
| "id"
| "name.first"
| "name.last"
| "address.city"
| "address.location.lat"
| "address.location.lng";
3 總結
本文總結了 TypeScript 中 infer 的常見用法,可以説 infer 是 TypeScript 裏各種類型體操的基礎,基於它可以實現各種「高級」類型。