chengaofeng
发布于 2024-07-25 / 8 阅读
0
0

Typescript深入infer

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;
}


评论