深入浅出 TS 条件类型的 infer 类型推断 🤨🤨🤨

TypeScript 中的 infer 关键字用于条件类型中,用于推断一个类型。这在处理复杂类型时非常有用,可以帮助我们提取或转换类型。

基本用法

infer 关键字只能在条件类型中使用,通常与泛型和 extends 关键字一起使用。它的语法如下:

ts 复制代码
type Moment<T> = T extends infer U ? U : never;

这里 T extends infer U 意味着我们试图推断类型 T 并将其赋值给 U。如果类型推断成功,那么 U 就是我们推断出的类型。

接下来我们可以用它来推断不同的类型,这里有几个例子:

ts 复制代码
type Moment<T> = T extends infer U ? U : never;

type StringType = Moment<string>; // string
type NumberType = Moment<number>; // number
type UnionType = Moment<string | number>; // string | number

interface User {
  name: string;
  age: number;
}

type UserType = Moment<User>; // User

在这些例子中,Moment<T> 实际上只是返回了 T 的类型,不进行任何转换或处理。这主要是用来演示条件类型和类型推断的基本用法。

常见示例

提取函数返回类型;

假设我们有一个函数类型,我们想要提取这个函数的返回类型,可以这样做:

ts 复制代码
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

type ExampleFunction = (x: number, y: string) => boolean;
type ReturnTypeOfExampleFunction = GetReturnType<ExampleFunction>; // boolean

在上面的这些代码中:

  1. T extends (...args: any[]) => infer R: 这部分检查类型 T 是否是一个函数类型。(...args: any[]) 表示该函数可以接受任意数量的参数。
  2. infer R: 如果 T 是一个函数类型,那么 infer R 将推断出函数的返回值类型,并将其赋给类型变量 R。
  3. ? R : never: 如果 T 是一个函数类型,则返回推断出的返回值类型 R;否则返回 never 类型。

提取数组元素类型

我们还可以使用 infer 来提取数组元素的类型:

ts 复制代码
type GetArrayElementType<T> = T extends (infer U)[] ? U : never;

type Moment = string[];
type Example1Array = Array<string>;

type ElementTypeOfExampleArray = GetArrayElementType<Moment>; // string
type ElementTypeOfExample1Array = GetArrayElementType<Example1Array>; //string

在这里,我们使用 T extends (infer U)[] 来推断数组元素的类型 U。其中 T 是 string[],U 是 string[] 中的是 string。

ts 复制代码
string[] extends (infer U)[ ]

值得注意的是,infer 声明仅在条件类型的 extends 子句中才允许使用,并且 infer 声明的类型变量只有在 true 分支中可用。

进阶示例

提取 Promise 的值类型

如果我们有一个 Promise 类型,我们可以提取其解析后的值类型:

ts 复制代码
type GetPromiseValueType<T> = T extends Promise<infer U> ? U : never;

// 示例
type ExamplePromise = Promise<number>;
type ValueTypeOfExamplePromise = GetPromiseValueType<ExamplePromise>; // number

在上面的这些代码中:

  1. T extends Promise<infer U>:这部分检查类型 T 是否是一个 Promise 类型。

  2. infer U:如果 T 是一个 Promise 类型,那么 infer U 将推断出 Promise 的值的类型,并将其赋给类型变量 U。

  3. ? U : never:如果 T 是一个 Promise 类型,则返回推断出的值的类型 U;否则返回 never 类型。

提取函数参数类型

有时我们需要获取一个函数的参数类型。可以使用 infer 来实现:

ts 复制代码
type GetParameters<T> = T extends (...args: infer P) => any ? P : never;

type ExampleFunction = (a: number, b: string) => void;
type Params = GetParameters<ExampleFunction>; // [number, string]

在上面的这些代码中:

  1. T extends (...args: infer P) => any:这部分检查类型 T 是否是一个函数类型。

  2. infer P:如果 T 是一个函数类型,那么 infer P 将推断出函数的参数类型,并将其赋给类型变量 P。

  3. ? P : never:如果 T 是一个函数类型,则返回推断出的参数类型 P;否则返回 never 类型。

提取构造函数参数类型

我们还可以使用 infer 来提取类构造函数的参数类型:

ts 复制代码
type ConstructorParameters<T> = T extends new (...args: infer P) => any
  ? P
  : never;

class ExampleClass {
  constructor(public a: number, public b: string) {}
}

type Params = ConstructorParameters<typeof ExampleClass>; // [number, string]

条件类型中的复杂推断

假设我们需要在条件类型中使用复杂的推断逻辑:

ts 复制代码
type IsArray<T> = T extends (infer U)[] ? U : never;
type IsFunction<T> = T extends (...args: any[]) => infer R ? R : never;

type ExtractType<T> = T extends any[]
  ? IsArray<T>
  : T extends (...args: any[]) => any
  ? IsFunction<T>
  : T;

// 示例
type ArrayType = ExtractType<string[]>; // string
type FunctionReturnType = ExtractType<() => number>; // number
type DefaultType = ExtractType<boolean>; // boolean

在这段代码中,如下:

ts 复制代码
type ExtractType<T> = T extends any[]
  ? IsArray<T>
  : T extends (...args: any[]) => any
  ? IsFunction<T>
  : T;
  1. T extends any[] ? IsArray<T> :如果 T 是一个数组类型,则返回 IsArray,即数组元素的类型。

  2. T extends (...args: any[]) => any ? IsFunction<T>: 如果 T 是一个函数类型,则返回 IsFunction,即函数的返回值类型。

  3. T:如果 T 既不是数组类型也不是函数类型,则返回 T 本身。

总结

infer 关键字用于条件类型中,以从其他类型中推断出一个新的类型变量。它允许在类型检查时提取和使用特定的子类型或属性,从而增强类型系统的表达能力和灵活性。简单来说,infer 可以帮助从复杂类型中自动提取出所需的部分类型。

TypeScript 中的 infer 关键字用于条件类型中,用于推断一个类型。这在处理复杂类型时非常有用,可以帮助我们提取或转换类型。

基本用法

infer 关键字只能在条件类型中使用,通常与泛型和 extends 关键字一起使用。它的语法如下:

ts 复制代码
type Moment<T> = T extends infer U ? U : never;

这里 T extends infer U 意味着我们试图推断类型 T 并将其赋值给 U。如果类型推断成功,那么 U 就是我们推断出的类型。

接下来我们可以用它来推断不同的类型,这里有几个例子:

ts 复制代码
type Moment<T> = T extends infer U ? U : never;

type StringType = Moment<string>; // string
type NumberType = Moment<number>; // number
type UnionType = Moment<string | number>; // string | number

interface User {
  name: string;
  age: number;
}

type UserType = Moment<User>; // User

在这些例子中,Moment<T> 实际上只是返回了 T 的类型,不进行任何转换或处理。这主要是用来演示条件类型和类型推断的基本用法。

常见示例

提取函数返回类型;

假设我们有一个函数类型,我们想要提取这个函数的返回类型,可以这样做:

ts 复制代码
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

type ExampleFunction = (x: number, y: string) => boolean;
type ReturnTypeOfExampleFunction = GetReturnType<ExampleFunction>; // boolean

在上面的这些代码中:

  1. T extends (...args: any[]) => infer R: 这部分检查类型 T 是否是一个函数类型。(...args: any[]) 表示该函数可以接受任意数量的参数。
  2. infer R: 如果 T 是一个函数类型,那么 infer R 将推断出函数的返回值类型,并将其赋给类型变量 R。
  3. ? R : never: 如果 T 是一个函数类型,则返回推断出的返回值类型 R;否则返回 never 类型。

提取数组元素类型

我们还可以使用 infer 来提取数组元素的类型:

ts 复制代码
type GetArrayElementType<T> = T extends (infer U)[] ? U : never;

type Moment = string[];
type Example1Array = Array<string>;

type ElementTypeOfExampleArray = GetArrayElementType<Moment>; // string
type ElementTypeOfExample1Array = GetArrayElementType<Example1Array>; //string

在这里,我们使用 T extends (infer U)[] 来推断数组元素的类型 U。其中 T 是 string[],U 是 string[] 中的是 string。

ts 复制代码
string[] extends (infer U)[ ]

值得注意的是,infer 声明仅在条件类型的 extends 子句中才允许使用,并且 infer 声明的类型变量只有在 true 分支中可用。

进阶示例

提取 Promise 的值类型

如果我们有一个 Promise 类型,我们可以提取其解析后的值类型:

ts 复制代码
type GetPromiseValueType<T> = T extends Promise<infer U> ? U : never;

// 示例
type ExamplePromise = Promise<number>;
type ValueTypeOfExamplePromise = GetPromiseValueType<ExamplePromise>; // number

在上面的这些代码中:

  1. T extends Promise<infer U>:这部分检查类型 T 是否是一个 Promise 类型。

  2. infer U:如果 T 是一个 Promise 类型,那么 infer U 将推断出 Promise 的值的类型,并将其赋给类型变量 U。

  3. ? U : never:如果 T 是一个 Promise 类型,则返回推断出的值的类型 U;否则返回 never 类型。

提取函数参数类型

有时我们需要获取一个函数的参数类型。可以使用 infer 来实现:

ts 复制代码
type GetParameters<T> = T extends (...args: infer P) => any ? P : never;

type ExampleFunction = (a: number, b: string) => void;
type Params = GetParameters<ExampleFunction>; // [number, string]

在上面的这些代码中:

  1. T extends (...args: infer P) => any:这部分检查类型 T 是否是一个函数类型。

  2. infer P:如果 T 是一个函数类型,那么 infer P 将推断出函数的参数类型,并将其赋给类型变量 P。

  3. ? P : never:如果 T 是一个函数类型,则返回推断出的参数类型 P;否则返回 never 类型。

提取构造函数参数类型

我们还可以使用 infer 来提取类构造函数的参数类型:

ts 复制代码
type ConstructorParameters<T> = T extends new (...args: infer P) => any
  ? P
  : never;

class ExampleClass {
  constructor(public a: number, public b: string) {}
}

type Params = ConstructorParameters<typeof ExampleClass>; // [number, string]

条件类型中的复杂推断

假设我们需要在条件类型中使用复杂的推断逻辑:

ts 复制代码
type IsArray<T> = T extends (infer U)[] ? U : never;
type IsFunction<T> = T extends (...args: any[]) => infer R ? R : never;

type ExtractType<T> = T extends any[]
  ? IsArray<T>
  : T extends (...args: any[]) => any
  ? IsFunction<T>
  : T;

// 示例
type ArrayType = ExtractType<string[]>; // string
type FunctionReturnType = ExtractType<() => number>; // number
type DefaultType = ExtractType<boolean>; // boolean

在这段代码中,如下:

ts 复制代码
type ExtractType<T> = T extends any[]
  ? IsArray<T>
  : T extends (...args: any[]) => any
  ? IsFunction<T>
  : T;
  1. T extends any[] ? IsArray<T> :如果 T 是一个数组类型,则返回 IsArray,即数组元素的类型。

  2. T extends (...args: any[]) => any ? IsFunction<T>: 如果 T 是一个函数类型,则返回 IsFunction,即函数的返回值类型。

  3. T:如果 T 既不是数组类型也不是函数类型,则返回 T 本身。

总结

infer 关键字用于条件类型中,以从其他类型中推断出一个新的类型变量。它允许在类型检查时提取和使用特定的子类型或属性,从而增强类型系统的表达能力和灵活性。简单来说,infer 可以帮助从复杂类型中自动提取出所需的部分类型。

相关推荐
寻找沙漠的人28 分钟前
前端知识补充—CSS
前端·css
GISer_Jing40 分钟前
2025前端面试热门题目——计算机网络篇
前端·计算机网络·面试
m0_7482455241 分钟前
吉利前端、AI面试
前端·面试·职场和发展
理想不理想v1 小时前
webpack最基础的配置
前端·webpack·node.js
pubuzhixing1 小时前
开源白板新方案:Plait 同时支持 Angular 和 React 啦!
前端·开源·github
2401_857600951 小时前
SSM 与 Vue 共筑电脑测评系统:精准洞察电脑世界
前端·javascript·vue.js
2401_857600951 小时前
数字时代的医疗挂号变革:SSM+Vue 系统设计与实现之道
前端·javascript·vue.js
GDAL1 小时前
vue入门教程:组件透传 Attributes
前端·javascript·vue.js
小白学大数据1 小时前
如何使用Selenium处理JavaScript动态加载的内容?
大数据·javascript·爬虫·selenium·测试工具
2402_857583491 小时前
基于 SSM 框架的 Vue 电脑测评系统:照亮电脑品质之路
前端·javascript·vue.js