infer 是 TypeScript 条件类型中用于动态推导子类型的关键字,仅可在 extends 左侧及 true 分支中使用;可提取函数首参、全部参数元组、构造函数参数,并在分布式条件类型中对联合类型的各成员分别推导。

infer 是 TypeScript 条件类型中用于“动态捕获类型”的关键字,它不声明具体类型,而是让编译器在类型检查过程中自动推导出某个结构中的子类型。配合条件类型使用时,infer 只能在 extends 的左侧类型中出现,并且只能在 true 分支中被引用。
提取单个参数类型(如第一个参数)
适用于需要约束或复用函数首个入参类型的场景,比如封装统一的事件处理器或校验函数:
- 写法:用
T extends (first: infer P, ...rest: any[]) => any捕获第一个参数 - 若函数只有一个参数,
infer P就是它的类型;若有多个,P仍精准对应第一个 - 若函数无参数(如
() => void),该条件不成立,返回never
示例:
type FirstParam<T> = T extends (first: infer P, ...rest: any[]) => any ? P : never;<br>function greet(name: string, age: number): void {}<br>type NameType = FirstParam<typeof greet>; // string
提取全部参数类型(元组形式)
这是最贴近实际开发需求的方式,尤其在高阶函数、装饰器或类型安全的 API 封装中常见:
- 写法:用
T extends (...args: infer P) => any捕获完整参数列表 - TypeScript 会把参数自动归纳为元组类型,保留顺序和可选性(如
[string, number?]) - 即使参数有 rest,也会正确映射为
[a: string, ...rest: number[]]这类带 rest 元素的元组
示例:
type Params<T> = T extends (...args: infer P) => any ? P : never;<br>function log(x: string, y?: number, ...z: boolean[]): void {}<br>type LogParams = Params<typeof log>; // [string, number?, ...boolean[]]
提取构造函数参数类型
常用于依赖注入、工厂模式或运行时反射场景,比如从 class 构造签名中获取初始化所需类型:
- 写法:用
T extends new (...args: infer P) => any捕获 new 调用时的参数 - 注意必须限定泛型约束为
T extends new (...args: any) => any,否则无法匹配构造签名 - 内置类型
ConstructorParameters<t></t>就是基于此逻辑实现的
示例:
type CtorParams<T> = T extends new (...args: infer P) => any ? P : never;<br>class User { constructor(public name: string, private id: number) {} }<br>type UserCtorArgs = CtorParams<typeof User>; // [string, number]
结合分布式条件类型做参数类型分发
当泛型参数是联合类型(如 ((x: A) => void) | ((y: B) => void))时,TypeScript 默认会对每个成员分别执行条件判断:
- 只要泛型参数是“裸类型参数”(即直接写
T,未包裹在其他类型中),就会触发分布式行为 - 此时
infer会分别对每个函数类型推导其参数,最终结果是各参数类型的联合 - 可用于统一处理多种回调签名,比如事件监听器类型收拢
示例:
type UnionFirstParam<T> = T extends (arg: infer P) => any ? P : never;<br>type Handler = ((id: number) => void) | ((name: string) => void);<br>type AnyParam = UnionFirstParam<Handler>; // number | string


















