infer的定义
infer 表示在 extends 条件语句中以点位符出现的等到使用时才推断出来的数据类型
type Fn = (params: string) => number;
// 第一种应用场景:获取函数的返回值类型
type TypeReturn = Fn extends (...args: any[]) => infer R ? R : any; // ReturnType = number
// 第二种应用场景:获取函数的参数类型
type ParamType<T> = T extends (params: infer P) => any ? P : T;
type Param = ParamType<Fn>; // Param = string
// 第三种应用场景:获取数组的元素类型
type ArrayType<T> = T extends (infer U)[] ? U : T;
type Item = ArrayType<number[]>; // Item = number
type ElementTypeOfArr<T> = T extends Array<infer P> ? P : never;
type Ele = ElementTypeOfArr<Array<{ name: string; age: number }>>; // Ele = { name: string; age: number }
infer 关键字用于在条件类型中引入类型推断。它允许你在条件类型的 extends 子句中推断出某个类型变量,并在条件类型的 true 分支中使用这个推断出的类型。
示例 1:提取 Promise 的返回类型
在处理异步编程时,我们经常需要知道一个 Promise 的返回类型。我们可以使用 infer
来提取这个类型。
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
async function fetchData(): Promise<string> {
return "data";
}
type DataType = UnwrapPromise<ReturnType<typeof fetchData>>; // DataType = string
示例 2:提取函数的参数类型
在某些情况下,我们可能需要提取函数的参数类型。infer
可以帮助我们做到这一点。
type ParametersType<T> = T extends (...args: infer P) => any ? P : never;
function logMessage(message: string, level: number): void {
console.log(`${level}: ${message}`);
}
type LogMessageParams = ParametersType<typeof logMessage>; // LogMessageParams = [string, number]
示例 3:提取类方法的返回类型
在面向对象编程中,我们可能需要提取类方法的返回类型。infer
也可以在这种情况下使用。
class UserService {
getUser(id: number): { name: string; age: number } {
return { name: "John", age: 30 };
}
}
type MethodReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type GetUserReturnType = MethodReturnType<UserService["getUser"]>; // GetUserReturnType = { name: string; age: number }
示例 4:提取数组元素类型
在处理数组时,我们可能需要提取数组的元素类型。infer 可以帮助我们做到这一点。
type ElementType<T> = T extends Array<infer U> ? U : T;
const numbers: number[] = [1, 2, 3];
type NumberElementType = ElementType<typeof numbers>; // NumberElementType = number
示例 5:提取元组类型中的第一个元素类型
在处理元组时,我们可能需要提取元组中的第一个元素类型。infer
可以帮助我们做到这一点。
type FirstElement<T> = T extends [infer U, ...any[]] ? U : never;
type Tuple = [string, number, boolean];
type FirstElementType = FirstElement<Tuple>; // FirstElementType = string
这些示例展示了 infer
在实际项目中的一些常见应用场景。通过使用 infer
,我们可以在类型系统中进行更复杂和灵活的类型推断,从而提高代码的可读性和可维护性。
示例6:Vue3源码中infer的应用
export function unref<T>(ref: T): T extends Ref<infer V> ? V : T {
return isRef(ref) ? (ref.value as any) : ref;
}