Typescript的infer到底怎么使用?

infer 是 TypeScript 中条件类型 的一个关键字,主要用于在条件类型中进行类型推断 。它允许我们在泛型条件类型中声明一个类型变量 ,然后从其他类型中推断出这个类型

基本语法

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

主要使用场景

1. 获取函数返回类型

typescr 复制代码
// 内置的 ReturnType 实现原理
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

function foo(): string {
  return "hello";
}

type FooReturn = MyReturnType<typeof foo>; // string

2. 获取函数参数类型

typescr 复制代码
// 获取第一个参数类型
type FirstParam<T> = T extends (first: infer P, ...rest: any[]) => any ? P : never;

// 获取所有参数类型(元组)
type Params<T> = T extends (...args: infer P) => any ? P : never;

function bar(x: number, y: string): void {}

type BarFirstParam = FirstParam<typeof bar>; // number
type BarParams = Params<typeof bar>; // [number, string]

3. 获取数组/元组元素类型

typescript

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

type StrArrayElement = ArrayElement<string[]>; // string
type NumArrayElement = ArrayElement<number[]>; // number

4. 获取 Promise 的解析类型

typescript 复制代码
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;

type PromiseString = Promise<string>;
type Unwrapped = UnwrapPromise<PromiseString>; // string

实际应用示例

示例1:提取对象值类型

typescr 复制代码
type ValueOf<T> = T extends { [key: string]: infer V } ? V : never;

type Obj = { a: number; b: string };
type Values = ValueOf<Obj>; // number | string

示例2:提取构造函数实例类型

typescript 复制代码
type InstanceType<T> = T extends new (...args: any[]) => infer R ? R : any;

class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

type AnimalInstance = InstanceType<typeof Animal>; // Animal

示例3:递归解包嵌套 Promise

typescript 复制代码
type DeepUnwrapPromise<T> = 
  T extends Promise<infer U> ? DeepUnwrapPromise<U> : T;

type NestedPromise = Promise<Promise<string>>;
type Result = DeepUnwrapPromise<NestedPromise>; // string

使用注意事项

1. 只能用在条件类型的 extends 子句中

typescr 复制代码
// ✅ 正确
type Example1<T> = T extends Array<infer U> ? U : never;

// ❌ 错误:infer 不能单独使用
type Example2<T> = infer U; // 编译错误

2. 多个 infer 可以同时使用

typescr 复制代码
type Zip<T, U> = T extends [infer A, ...infer RestT]
  ? U extends [infer B, ...infer RestU]
    ? [[A, B], ...Zip<RestT, RestU>]
    : []
  : [];

type Result = Zip<[1, 2], ['a', 'b']>; // [[1, 'a'], [2, 'b']]

3. 协变位置 vs 逆变位置

typescript 复制代码
// infer 在协变位置(返回类型)
type GetReturnType<T> = T extends () => infer R ? R : never;

// infer 在逆变位置(参数类型)
type GetArgType<T> = T extends (arg: infer A) => any ? A : never;

实战技巧

1. 类型守卫与 infer

typescr 复制代码
function isPromise<T>(value: any): value is Promise<T> {
  return value && typeof value.then === 'function';
}

async function handle<T>(input: T | Promise<T>): Promise<T> {
  if (isPromise(input)) {
    // 这里 input 被推断为 Promise<T>
    return input;
  }
  return Promise.resolve(input);
}

2. 构建实用类型工具

typescr 复制代码
// 提取所有方法的返回类型
type MethodsReturnType<T> = {
  [K in keyof T]: T[K] extends (...args: any[]) => infer R ? R : never;
};

// 提取特定属性的类型
type PropType<T, K extends keyof T> = T extends { [P in K]: infer V } ? V : never;

总结

infer 的核心作用:在条件类型中提取未知类型的内部结构。它是 TypeScript 类型系统的高级特性,常用于:

  1. 类型提取:从已有类型中提取部分类型信息
  2. 类型转换:将一个类型转换为另一种形式
  3. 类型推导:根据上下文推导出具体类型
  4. 工具类型创建:构建复杂的实用类型工具

掌握 infer 的关键是多实践,从简单的函数返回类型提取开始,逐步应用到更复杂的类型操作中。

相关推荐
一袋米扛几楼987 分钟前
【Git】规范化协作:详解 GitHub 工作流中的 Issue、Branch 与 Pull Request 最佳实践
前端·git·github·issue
网络点点滴20 分钟前
前端与后端的区别与联系
前端
EnCi Zheng1 小时前
M5-markconv自定义CSS样式指南 [特殊字符]
前端·css·python
kyriewen1 小时前
你的网页慢,用户不说直接走——前端性能监控教你“读心术”
前端·性能优化·监控
广州华水科技1 小时前
北斗GNSS变形监测在大坝安全监测中的应用与优势分析
前端
前端老石人1 小时前
前端开发中的 URL 完全指南
开发语言·前端·javascript·css·html
CAE虚拟与现实1 小时前
五一假期闲来无事,来个前段、后端的说明吧
前端·后端·vtk·three.js·前后端
Sarvartha1 小时前
三目运算符
linux·服务器·前端
晓晨的博客1 小时前
ROS1录制的bag包转换为ROS2格式
前端·chrome
Wect1 小时前
LeetCode 72. 编辑距离:动态规划经典题解
前端·算法·typescript