首页 / TypeScript 入门教程 / infer 关键字

TypeScript 入门教程

infer 关键字

本教程共 80 篇 · 第 49 篇 · 更新于 2026-08-10 · 约 12 分钟阅读

TypeScriptTypeScript 入门教程infer条件类型类型推断

本节目标:理解 infer 在条件类型中的作用——从复杂类型中”抽取”子类型,掌握函数返回类型、数组元素、Promise 值的提取方法。

infer 是什么

infer 只能在条件类型的 extends 子句中使用,用于声明一个待推断的类型变量。它的工作方式可以这么理解:

如果 T 的形状匹配某个模式,就把模式中的某个部分”抓出来”存到变量里。

// 如果 T 是数组,就把元素类型抓出来
type ElementType<T> = T extends (infer U)[] ? U : never;

type A = ElementType<string[]>; // string
type B = ElementType<number[]>; // number
type C = ElementType<number>;   // never(不是数组,匹配失败)

infer U 没有初始值——它的值由 TypeScript 根据 T 的实际形状”反向推导”出来。

为什么需要 infer

没有 infer 的时候,你想从一个 Promise<User> 里拿到 User 的类型,唯一的办法是手动再写一遍:

// 没有 infer——手动维护
type User = { id: number; name: string };
type PromiseUser = Promise<User>;
// 想在别处用 User 类型?要么 import,要么再写一遍

infer 让你从类型结构里”掏”出需要的那部分:

type Awaited<T> = T extends Promise<infer V> ? V : never;
type User = Awaited<Promise<{ id: number; name: string }>>;
// User = { id: number; name: string }

这是 TypeScript 内置工具类型 Awaited<T> 的实现原理。

常见使用场景

提取函数返回值

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

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

function getUser() {
  return { id: 1, name: "王五" };
}

type User = ReturnType<typeof getUser>;
// User = { id: number; name: string }

先用 typeof getUser 拿到函数类型,再用 ReturnType 拆出返回值类型。改函数的 return 语句,User 类型自动跟着变,不用手动同步。

提取函数参数

// 提取第一个参数的类型
type FirstParam<T> = T extends (first: infer P, ...rest: any[]) => any ? P : never;

function sendMessage(to: string, content: string) { /* ... */ }
type To = FirstParam<typeof sendMessage>; // string

提取数组元素

前面已经用过了。注意数组的写法不止一种 T[],所以也可以写成:

type ElementType<T> = T extends Array<infer U> ? U : never;

这两种写法对普通数组等价,但 Array<infer U> 更能体现”泛型匹配”的思维。

Promise 解包(递归 infer)

infer 和递归条件类型配合,可以处理嵌套的 Promise:

type Awaited<T> = T extends Promise<infer V>
  ? V extends Promise<any>
    ? Awaited<V>   // 递归:继续解包
    : V
  : T;

type A = Awaited<Promise<string>>;           // string
type B = Awaited<Promise<Promise<number>>>; // number

提取构造器实例

type InstanceType<T extends abstract new (...args: any[]) => any> =
  T extends abstract new (...args: any[]) => infer R ? R : any;

class Dog {}
type DogInstance = InstanceType<typeof Dog>; // Dog

这也是一个内置工具类型的实现方式。

多个 infer

一个条件类型里可以用多个 infer,在元组匹配时特别有用:

// 提取元组的前两个元素
type FirstTwo<T> = T extends [infer A, infer B, ...any[]] ? [A, B] : never;

type Tuple = [string, number, boolean];
type Result = FirstTwo<Tuple>; // [string, number]

...any[] 匹配剩余的所有元素——这样就不关心元组后面还有几个元素了。

infer 的位置限制

infer 只能出现在条件类型的 extends 子句中,而且必须在 true 分支里被使用(至少要被返回)。以下写法都是错的:

// ❌ 不在条件类型中
type Bad<T> = infer U;

// ❌ 不在 extends 子句里
type AlsoBad<T> = T extends string ? infer U : never;

// ✅ 必须在 extends 的右侧
type Good<T> = T extends Array<infer U> ? U : never;

小结

  • infer 在条件类型中声明待推断的类型变量
  • 最常用的有:infer R(返回值)、infer U(数组元素)、infer V(Promise 值)
  • 可以和递归类型配合做嵌套解包
  • 多个 infer 可以同时使用,常用于元组提取
  • infer 只能放在条件类型 extends 的右侧