学习笔记学习笔记
主站博客
面试
前端
开发工具
Cesium
GitHub
主站博客
面试
前端
开发工具
Cesium
GitHub
  • 前端
  • 微前端

    • qiankun

      • qiankun 实现隔离原理
  • 模块化

    • 导入

      • js导入的几种形式
      • import.meta.glob

        • 详解 import.meta.glob
    • JSX

      • /fe/module/jsx/
      • pragma: jsx 如何理解
      • Rollup+Babel 对比 Gulp+TypeScript
    • npm link

      • npm link
    • npm-vs-gitsubmodule

      • npm和git submodule 对比
  • 性能优化

    • 性能优化
    • 代码分隔

      • 代码分隔
  • TypeScript

    • ts的infer介绍
    • ts的工具类型(Utility Types)

ts的infer介绍

在 TypeScript 中,infer 是条件类型(Conditional Types)中用于声明一个待推断的类型变量的关键字。它的核心作用是:在类型匹配过程中,让 TypeScript 自动推导并捕获某个位置的类型,从而简化复杂的类型提取、转换逻辑。

infer 只能在条件类型的 extends 子句中使用,语法通常为 infer 类型变量名,用于“占位”需要推断的类型。

核心应用场景

infer 的主要价值在于从复杂类型中“提取”或“推导”出子类型,常见场景包括:

1. 提取函数的返回值类型

最经典的场景之一:从函数类型中提取其返回值类型。

TypeScript 内置的 ReturnType<T> 就是基于 infer 实现的:

// 定义:从函数类型 T 中提取返回值类型
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : T;

// 示例
function getUser() {
  return { name: "张三", age: 20 };
}

// 提取 getUser 函数的返回值类型 { name: string; age: number }
type User = MyReturnType<typeof getUser>;

原理:当 T 匹配“函数类型”时,infer R 会自动捕获该函数的返回值类型,最终通过 R 返回。

2. 提取函数的参数类型

类似地,可以提取函数的参数类型(或某个参数的类型)。

TypeScript 内置的 Parameters<T> 也基于 infer 实现:

// 定义:从函数类型 T 中提取参数类型组成的元组
type MyParameters<T> = T extends (...args: infer P) => any ? P : never;

// 示例
function greet(name: string, age: number) {
  return `Hello, ${name}, age ${age}`;
}

// 提取参数类型 [string, number]
type GreetParams = MyParameters<typeof greet>; 

// 提取第一个参数的类型 string
type FirstParam = GreetParams[0];

3. 提取数组/元组的元素类型

从数组或元组中提取元素类型,或特定位置的元素类型:

// 提取数组的元素类型
type ArrayItem<T> = T extends Array<infer Item> ? Item : T;

// 示例
type NumberItem = ArrayItem<number[]>; // number
type StringItem = ArrayItem<string[]>; // string


// 提取元组的第一个元素类型
type FirstElement<T> = T extends [infer First, ...any[]] ? First : never;

// 示例
type T1 = FirstElement<[string, number, boolean]>; // string
type T2 = FirstElement<[]>; // never(空元组无第一个元素)

4. 提取 Promise 包裹的类型

从 Promise<T> 中提取内部的 T 类型(即“解包”Promise):

// 定义:从 Promise<T> 中提取 T
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;

// 示例
type P1 = UnwrapPromise<Promise<string>>; // string
type P2 = UnwrapPromise<Promise<number[]>>; // number[]
type P3 = UnwrapPromise<string>; // string(非 Promise 类型直接返回自身)

甚至可以处理嵌套的 Promise(如 Promise<Promise<T>>):

// 递归解包嵌套 Promise
type DeepUnwrapPromise<T> = T extends Promise<infer U> 
  ? DeepUnwrapPromise<U> 
  : T;

type P4 = DeepUnwrapPromise<Promise<Promise<boolean>>>; // boolean

5. 提取字符串字面量的部分内容

结合模板字符串类型,可以从字符串字面量中提取特定部分:

// 从 "前缀:值" 格式的字符串中提取 "值"
type ExtractValue<T> = T extends `${string}:${infer Value}` ? Value : T;

// 示例
type V1 = ExtractValue<"user:123">; // "123"
type V2 = ExtractValue<"role:admin">; // "admin"
type V3 = ExtractValue<"nocolon">; // "nocolon"(不匹配格式则返回自身)

6. 处理联合类型的推断

在联合类型中,infer 会遵循“ distributive conditional types”规则,对联合类型的每个成员单独推断:

type UnwrapArray<T> = T extends Array<infer Item> ? Item : T;

// 对联合类型 (string[] | number[] | boolean) 推断
type Result = UnwrapArray<string[] | number[] | boolean>; 
// 等价于 UnwrapArray<string[]> | UnwrapArray<number[]> | UnwrapArray<boolean>
// 结果:string | number | boolean

核心价值

infer 的本质是让 TypeScript 自动完成“类型提取”的脏活,避免手动编写冗长的类型逻辑。它极大增强了 TypeScript 类型系统的灵活性,使得复杂的类型转换(如函数参数提取、Promise 解包、数组元素提取等)可以用简洁的方式实现。

在实际开发中,infer 常用于封装通用类型工具(如上述示例),或在库/框架中处理复杂的类型映射(如 React 中的 React.ComponentProps 就是通过 infer 提取组件的 props 类型)。

在 GitHub 上编辑此页
上次更新:
贡献者: 国wei
Next
ts的工具类型(Utility Types)