infer 关键字
本教程共 80 篇 · 第 49 篇 · 更新于 2026-08-10 · 约 12 分钟阅读
本节目标:理解
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的右侧