在 TypeScript 中,infer 关键字是一个强大的工具,主要用于条件类型中进行类型推断。以下是 infer 的使用方法、技巧和常见场景:

  1. 基本使用方法:

infer 通常在条件类型的”真”分支中使用,用于从类型中提取类型信息。

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
  1. 提取函数返回类型:
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
 
function foo() { return 42; }
type FooReturn = GetReturnType<typeof foo>; // number
  1. 提取函数参数类型:
type GetFirstArgument<T> = T extends (first: infer F, ...rest: any[]) => any ? F : never;
 
function bar(x: string, y: number) { return x + y; }
type BarFirstArg = GetFirstArgument<typeof bar>; // string
  1. 提取 Promise 的 resolved 类型:
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
 
type PromiseString = Promise<string>;
type UnwrappedPromiseString = UnwrapPromise<PromiseString>; // string
  1. 提取数组元素类型:
type ArrayElement<T> = T extends (infer E)[] ? E : never;
 
type Numbers = ArrayElement<number[]>; // number
  1. 递归使用 infer:
type Flatten<T> = T extends Array<infer U> ? Flatten<U> : T;
 
type NestedArray = [1, [2, [3, 4]], 5];
type FlattenedArray = Flatten<NestedArray>; // number
  1. 在映射类型中使用 infer:
type ObjectToUnion<T> = T extends { [K in keyof T]: infer U } ? U : never;
 
type Obj = { a: string, b: number, c: boolean };
type Union = ObjectToUnion<Obj>; // string | number | boolean
  1. 提取构造函数参数类型:
type ConstructorParameters<T> = T extends new (...args: infer P) => any ? P : never;
 
class Example {
  constructor(a: number, b: string) {}
}
 
type ExampleParams = ConstructorParameters<typeof Example>; // [number, string]
  1. 条件推断:
type IsArray<T> = T extends (infer E)[] ? true : false;
 
type CheckArray1 = IsArray<number[]>; // true
type CheckArray2 = IsArray<string>; // false

这些例子展示了 infer 关键字在类型操作中的多种用途。它能够帮助我们创建更灵活、更强大的类型定义,特别是在需要从复杂类型中提取或推断类型信息时非常有用。在编写高级类型、类型工具或泛型库时,infer 是一个不可或缺的工具。