Skip to content

infer extends 简化类型编程

infer 关键字

infer 关键字是在 TypeScript 2.8 引入的,用于在条件类型中创建临时类型变量,允许我们从已有的类型中提取信息。它通常与条件类型(extends)一起使用来动态地推断类型

typescript
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

function foo() {
    return { x: 10, y: 3 };
}

type FooReturnType = GetReturnType<typeof foo>; // { x: number; y: number; }

在这个例子中,infer R 就是用来捕获函数返回类型的占位符。当 TypeScript 遇到 T extends (...args: any[]) => infer R 的时候,它会试图匹配 T 是否符合函数签名的形式,并将实际的返回类型赋给 R

extends 关键字

extends 关键字则主要用于指定泛型参数的约束或定义类与接口之间的继承关系。在条件类型中,extends 可以用来比较两个类型是否兼容,并根据结果选择不同的分支

条件类型中的 extends

在条件类型中,extends 被用来检查左边的类型是否可以分配给右边的类型。如果可以,则选择 true 分支;否则选择 false 分支。

例如,我们可以使用 extends 来过滤出联合类型中满足特定约束的成员:

typescript
type IsString<T> = T extends string ? true : false;
type Test1 = IsString<"hello">; // true
type Test2 = IsString<42>;       // false

结合使用 inferextends

当你需要从复杂类型中提取部分类型信息时,inferextends 的组合变得特别有用。以下是一些常见的应用场景:

  • 提取函数参数类型

    typescript
    type ParametersType<T> = T extends (...args: infer P) => any ? P : never;
  • 提取数组元素类型

    typescript
    type ElementType<T> = T extends (infer U)[] ? U : never;
  • 提取Promise解析值类型

    typescript
    type UnwrapPromise<T> = T extends Promise<infer U> ? U : never;

这些模式展示了如何利用 inferextends 简化原本可能需要手动定义的类型操作。例如,如果你想提取一个对象属性的类型,你可以这样写:

typescript
type PropType<T, K extends keyof T> = T extends { [P in K]: infer U } ? U : never;

这比直接为每个属性手动定义类型要高效得多,特别是在处理大型或动态数据结构时。