1 什么是「infer」
1.1 概念
infer 只能在 条件类型(conditional types) 中使用,用来 在类型推断时声明一个待推断的类型变量。
语法为:
typescript
T extends SomeType<infer U> ? U : never
可以这么理解:
- 如果
T能匹配SomeType<某个类型>的结构 - 那么把内部类型推断为
U - 然后返回
U
1.2 特点
1.2.1 只能在 extends ? : 中使用
不能单独写,比如下边这么写就是错的:
typescript
type A = infer T;
1.2.2 右侧的类型结构必须能匹配
typescript
type A<T> = T extends [infer U] ? U : never;
type B = A<[string]>; // string
type C = A<string>; // never
2 基本用法
2.1 提取函数返回值类型
typescript
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type A = ReturnType<() => number>;
// A = number
infer R 就是 推断函数的返回值类型。
2.2 提取参数类型
typescript
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 提取数组元素类型
typescript
type ElementOf<T> = T extends (infer U)[] ? U : never;
type A = ElementOf<string[]>;
// A = string
2.4 提取 tuple 的某个元素
typescript
type First<T> = T extends [infer F, ...any[]] ? F : never;
type A = First<[string, number, boolean]>;
// A = string
在这个例子中,我们提取的是 tuple 的第一个元素。
2.5 提取对象中某个 key 的类型
typescript
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 对象路径提取
typescript
type Path<T> = {
[K in keyof T]:
T[K] extends object
? `${string & K}.${Path<T[K]>}`
: `${string & K}`;
}[keyof T];
假设说我们有这么一个类型:
typescript
type User = {
id: number;
name: {
first: string;
last: string;
};
address: {
city: string;
location: {
lat: number;
lng: number;
};
};
};
执行 Path:
typescript
type UserPath = Path<User>;
之后得到的结果展开就是:
typescript
type UserPath =
| "id"
| "name.first"
| "name.last"
| "address.city"
| "address.location.lat"
| "address.location.lng";
3 总结
本文总结了 TypeScript 中 infer 的常见用法,可以说 infer 是 TypeScript 里各种类型体操的基础,基于它可以实现各种「高级」类型。