- 文档
- 教程
【免费下载链接】typescript-book
The Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.
infer是 TypeScript 条件类型中用于从依赖泛型参数的类型中提取(推断)该泛型参数的核心关键字,它让类型定义从"显式声明"走向"自动推导",是编写灵活、可复用类型工具(如ReturnType、Parameters)的底层基石。本文将基于开源仓库 typescript-book 中第 42 节内容展开,结合仓库内条件类型、预定义条件类型与类型操纵等章节,系统讲解infer的语法、工作方式、约束条件与典型实战模式,读完即可在业务代码中熟练编写自己的类型提取工具。
从条件类型说起:infer的语法基础
infer只能出现在条件类型的extends分支中。条件类型(Conditional Types)允许我们"根据条件决定最终类型",其语法由extends关键字与三元运算符构成(第 40 节):
type IsArray<T> = T extends any[] ? true : false; const myArray = [1, 2, 3]; const myNumber = 42; type IsMyArrayAnArray = IsArray<typeof myArray>; // Type true type IsMyNumberAnArray = IsArray<typeof myNumber>; // Type false在这段代码中,T extends any[]是"条件",true与false分别是条件成立与不成立时的结果类型。条件类型解决的是"是或否"的判定问题,而infer解决的则是"如果是,那它到底是什么"的提取问题——它是在条件成立的场景下,声明一个可被 TypeScript 编译器自动推断的"占位类型变量"。
infer的核心用法:从依赖类型中提取泛型参数
关联文档原文(infer-type-inference-in-conditional-types.md): Le mot-clé
inferest utilisé dans les types conditionnels afin d'inférer (extraire) le type d'un paramètre générique depuis un type qui en dépend. Il permet ainsi d'écrire des définitions de types plus souples et réutilisables. (infer关键字用于条件类型中,以便从依赖泛型参数的类型中推断(提取)该泛型参数的类型,从而编写更灵活、可复用的类型定义。)
下面是文档给出的最典型示例:
type ElementType<T> = T extends (infer U)[] ? U : never; type Numbers = ElementType<number[]>; // number type Strings = ElementType<string[]>; // string逐行拆解:
ElementType<T>是一个泛型条件类型;T extends (infer U)[]判断T是否是一个数组类型。若成立,U会被自动推断为该数组的元素类型;- 条件成立时返回
U(即数组元素类型),不成立时返回never(never 类型 表示"永不出现的值",在此充当"提取失败"的兜底); - 代入
number[]时,U被推断为number;代入string[]时,U被推断为string。
注意U不需要在泛型参数列表中显式声明——它完全由编译器从(infer U)[]的结构中自动推导,这正是infer名称(inference,推断)的由来。
从函数签名提取参数类型
infer不仅适用于数组,也适用于函数签名。仓库 type-manipulation.md 第 49~57 行给出了一个从函数参数中提取类型的示例:
type ExtractParam<T> = T extends (param: infer P) => any ? P : never; type MyFunction = (name: string) => number; type ParamType = ExtractParam<MyFunction>; // string这里(param: infer P) => any匹配任意函数类型,并将第一个参数的类型推断为P,最终ParamType得到string。这说明infer的"位置占位"能力可以作用于函数的参数位、返回位等多种结构位。
infer的约束条件与注意事项
根据官方语义与仓库文档,使用infer需遵守以下约束:
| 约束 | 说明 |
|---|---|
| 仅限条件类型 | infer只能出现在条件类型T extends X ? Y : Z的X(extends 右侧)中,不能在普通类型别名、接口或类中单独使用 |
| 位置绑定 | infer U必须出现在被匹配结构的具体位置上(如(infer U)[]的数组内部、(param: infer P)的参数位、() => infer R的返回位),编译器根据该位置推断U |
| 联合类型的分配 | 条件类型在传入裸类型参数(裸的联合类型)时会逐个成员分配执行(见分配条件类型),infer也会随之在每个成员上独立推断 |
| 推断失败返回兜底 | 当T不满足匹配结构时走else分支,惯例上返回never表示"无法提取" |
一个直接相关的推论:infer的位置决定提取结果。例如将infer放在返回位即可提取函数返回值:
type GetReturn<T> = T extends (...args: any[]) => infer R ? R : never; type Add = (x: number, y: number) => number; type Result = GetReturn<Add>; // number这与仓库 type-from-func-return.md 讨论的"从函数实现自动推断返回类型"呼应:前者是编译器对函数体的推断,后者则是我们用infer从函数类型签名中主动提取。
实战:infer的进阶模式
模式一:推断元组(Tuple)中指定位置的类型
结合仓库 fixed-length-tuple.md 对定长元组的介绍,infer可与元组结构配合提取特定元素类型:
type First<T extends any[]> = T extends [infer F, ...any[]] ? F : never; type Tuple = [string, number, boolean]; type FirstType = First<Tuple>; // string[infer F, ...any[]]通过 rest 元素匹配元组剩余部分,将F绑定到首元素位置。
模式二:infer与分配条件类型的组合
仓库 distributive-conditional-types.md 展示了条件类型对联合类型的分配行为。当infer与联合类型相遇时,结果会按成员合并:
type ElementType<T> = T extends (infer U)[] ? U : never; type Union = ElementType<(string | number)[]>; // string | number这里(string | number)[]作为一个整体匹配(infer U)[],U被推断为string | number,展示了infer与联合类型的自然协作。
模式三:逐层递归解包(Awaited 的思路)
infer允许在类型层面做"递归解包"。仓库 type-manipulation.md 第 81~87 行提到的内置工具类型Awaited<T>本质上是"递归展开 Promise"的infer用法,我们可以手写一个简化版:
type Unwrap<T> = T extends Promise<infer R> ? Unwrap<R> : T; type A = Unwrap<Promise<Promise<string>>>; // string每次匹配Promise<infer R>就把R取出,若R仍是 Promise 则继续递归,直到遇到非 Promise 类型为止。
infer与内置工具类型的血缘关系
infer并非冷门技巧——TypeScript 语言内置的多个常用工具类型正是基于它实现的。仓库 predefined-conditional-types.md 列举了这些内置条件类型,其中两个最典型的infer应用是:
ReturnType<Type>:提取函数类型Type的返回类型;Parameters<Type>:提取函数类型Type的参数类型(结果为元组)。
它们的实现逻辑与前面手写的GetReturn、ExtractParam完全同源,可以理解为"官方版的 infer 提取工具":
type Func = (name: string) => number; type R = ReturnType<Func>; // number type P = Parameters<Func>; // [name: string]此外,仓库 type-manipulation.md 还列出了更多依赖类似机制的类型工具:ConstructorParameters<T>(提取构造函数参数,内部通过new (...args: infer P) => any匹配构造函数签名)、InstanceType<T>、ThisParameterType<T>、OmitThisParameter<T>等。理解infer,就等于掌握了这批内置工具类型的底层实现原理,遇到官方工具不满足需求时,完全可以照着同样的思路写出自定义的提取类型。
小结
infer只能用于条件类型的extends分支中,作用是从被匹配的结构中自动推断并提取某个位置上的类型;- 经典形态
T extends (infer U)[] ? U : never可提取数组元素类型,返回位() => infer R可提取函数返回类型,参数位(param: infer P)可提取参数类型; - 提取失败时惯例返回
never作为兜底; - 它是
ReturnType、Parameters、Awaited等内置工具类型的实现基石,也是编写自定义类型提取工具的通用手法; - 相关延伸阅读:条件类型、分配条件类型、预定义条件类型、类型操纵。
- 文档
- 教程
【免费下载链接】typescript-book
The Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.
相关推荐
《The Concise TypeScript Book》精读:条件类型中的 infer 类型推断
《The Concise TypeScript Book》精读:条件类型中的 infer 类型推断 在 TypeScript 的类型系统中, infer 是条件
文档教程Wekan 自定义主题与 CSS 主题开发完全指南:从 Stylish 覆盖到内置主题系统
Wekan 自定义主题与 CSS 主题开发完全指南:从 Stylish 覆盖到内置主题系统 本文是一份面向 Wekan 开发者与高级用户的主题定制实战指南。文章
文档教程The Concise TypeScript Book:Conditional 类型中的 `infer` 类型推断实战指南
The Concise TypeScript Book:Conditional 类型中的 infer 类型推断实战指南 本篇指南围绕开源项目 typ/types
文档教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考