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
在上面的这些代码中:
T extends (...args: any[]) => infer R
: 这部分检查类型 T 是否是一个函数类型。(...args: any[]) 表示该函数可以接受任意数量的参数。infer R
: 如果 T 是一个函数类型,那么 infer R 将推断出函数的返回值类型,并将其赋给类型变量 R。? 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
在上面的这些代码中:
-
T extends Promise<infer U>
:这部分检查类型 T 是否是一个 Promise 类型。 -
infer U
:如果 T 是一个 Promise 类型,那么 infer U 将推断出 Promise 的值的类型,并将其赋给类型变量 U。 -
? 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]
在上面的这些代码中:
-
T extends (...args: infer P) => any
:这部分检查类型 T 是否是一个函数类型。 -
infer P
:如果 T 是一个函数类型,那么 infer P 将推断出函数的参数类型,并将其赋给类型变量 P。 -
? 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;
-
T extends any[] ? IsArray<T>
:如果 T 是一个数组类型,则返回 IsArray,即数组元素的类型。 -
T extends (...args: any[]) => any ? IsFunction<T>
: 如果 T 是一个函数类型,则返回 IsFunction,即函数的返回值类型。 -
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
在上面的这些代码中:
T extends (...args: any[]) => infer R
: 这部分检查类型 T 是否是一个函数类型。(...args: any[]) 表示该函数可以接受任意数量的参数。infer R
: 如果 T 是一个函数类型,那么 infer R 将推断出函数的返回值类型,并将其赋给类型变量 R。? 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
在上面的这些代码中:
-
T extends Promise<infer U>
:这部分检查类型 T 是否是一个 Promise 类型。 -
infer U
:如果 T 是一个 Promise 类型,那么 infer U 将推断出 Promise 的值的类型,并将其赋给类型变量 U。 -
? 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]
在上面的这些代码中:
-
T extends (...args: infer P) => any
:这部分检查类型 T 是否是一个函数类型。 -
infer P
:如果 T 是一个函数类型,那么 infer P 将推断出函数的参数类型,并将其赋给类型变量 P。 -
? 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;
-
T extends any[] ? IsArray<T>
:如果 T 是一个数组类型,则返回 IsArray,即数组元素的类型。 -
T extends (...args: any[]) => any ? IsFunction<T>
: 如果 T 是一个函数类型,则返回 IsFunction,即函数的返回值类型。 -
T
:如果 T 既不是数组类型也不是函数类型,则返回 T 本身。
总结
infer 关键字用于条件类型中,以从其他类型中推断出一个新的类型变量。它允许在类型检查时提取和使用特定的子类型或属性,从而增强类型系统的表达能力和灵活性。简单来说,infer 可以帮助从复杂类型中自动提取出所需的部分类型。