深入浅出 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 可以帮助从复杂类型中自动提取出所需的部分类型。

相关推荐
还是鼠鼠1 小时前
图书管理系统 Axios 源码__新增图书
前端·javascript·vscode·ajax·前端框架·node.js·bootstrap
还是鼠鼠4 小时前
图书管理系统 Axios 源码 __删除图书功能
前端·javascript·vscode·ajax·前端框架·node.js·bootstrap
轻口味4 小时前
Vue.js `Suspense` 和异步组件加载
前端·javascript·vue.js
m0_zj5 小时前
8.[前端开发-CSS]Day08-图形-字体-字体图标-元素定位
前端·css
还是鼠鼠6 小时前
图书管理系统 Axios 源码__编辑图书
前端·javascript·vscode·ajax·前端框架
北极象6 小时前
vue3中el-input无法获得焦点的问题
前端·javascript·vue.js
百度网站快速收录6 小时前
网站快速收录:如何优化网站头部与底部信息?
前端·html·百度快速收录·网站快速收录
Loong_DQX6 小时前
【react+redux】 react使用redux相关内容
前端·react.js·前端框架
GISer_Jing6 小时前
react redux监测值的变化
前端·javascript·react.js
engchina6 小时前
CSS 样式化表格:从基础到高级技巧
前端·css