在这篇短文里,我们会通过 3 个例子来理解 infer 关键字的作用。
先来看一个例子:
type FlattenIfArray<T> = T extends Array<infer R> ? R : T;
我们来分析一下以上代码:
- 首先判断泛型
T是否数组类型; - 如果是数组类型,将数组成员类型
R抽出来并返回; - 如果不是数组类型,则原样返回
T;
由于数组类型的定义有两种写法,所以上面的代码还有另外一种写法:
type FlattenIfArray<T> = T extends (infer R)[] ? R : T;
再来看一个例子:
type Unpromisify<T> = T extends Promise<infer R> ? R : T;
- 首先判断泛型
T是否 Promise 的子集; - 如果是,将 Promise 中的泛型
R抽出来并返回; - 如果不是则原样返回
T;
再来看一个复杂一点的例子:
type FunctionWithOneObjectArgument<P extends { [x: string]: any }, R> = (
props: P,
) => R;
type DestructuredArgsOfFunction<
F extends FunctionWithOneObjectArgument<any, any>
> = F extends FunctionWithOneObjectArgument<infer P, any> ? P : never;
const myFunction = (props: { x: number; y: number }): string => {
return 'ok';
};
const props: DestructuredArgsOfFunction<typeof myFunction> = {
x: 1,
y: 2,
};
代码分析:
-
FunctionWithOneObjectArgument接收两个泛型P和R,然后返回一个函数签名(props: P) => R,而P extends { [x: string]: any }这部分则将参数类型P限定为一个对象。 -
DestructuredArgsOfFunction接收一个泛型F,然后判断F是否FunctionWithOneObjectArgument<P, R>的子集,如果是子集则将其中的P类型抽出来返回,如果不是则返回never -
typeof myFunction会返回myFunction的函数签名,也就是(props: { x: number; y: number }): string -
DestructuredArgsOfFunction<typeof myFunction>就相当于DestructuredArgsOfFunction<(props: { x: number; y: number }): string>,我们可以将它代入到DestructuredArgsOfFunction的类型定义中,容易看出infer P会将P推导为{ x: number; y: number },然后我们返回了P,所以props变量的类型就是{ x: number; y: number }了。