typescript 条件类型通过 t extends u ? x : y 实现类型层面的分支判断,具有分布式求值、infer 提取和递归组合等核心特性。

在 TypeScript 中,条件类型是实现高级类型推导的核心机制,它让类型能根据其他类型的状态“分支判断”,类似 JavaScript 中的三元表达式,但作用于类型层面。关键在于理解 extends 的“分配律”行为、结合 infer 提取结构,再通过嵌套或组合构建逻辑。
用 T extends U ? X : Y 做基础类型分流
条件类型语法直观,但实际行为比表面复杂:当左侧类型是裸类型参数(如 T)且传入联合类型时,TypeScript 会自动“分布式”求值——对每个成员分别计算,再合并结果。
- 例如:
type Boxed<t> = T extends string ? { value: T } : T extends number ? { num: T } : never;</t>
传入Boxed<string number></string>得到{ value: string } | { num: number },不是单个对象类型。 - 若想禁用分布式行为,可将类型“包裹”起来,比如写成
[T] extends [string] ? ... : ...。
配合 infer 提取嵌套结构
infer 是在条件类型中声明类型变量的关键字,常用于从函数类型、元组、Promise 等结构中“解包”出内部类型。
- 提取函数返回值:
type ReturnType<t> = T extends (...args: any) => infer R ? R : never;</t> - 提取 Promise 解析类型:
type Awaited<t> = T extends Promise<infer u> ? U : T;</infer></t>(这是 TypeScript 内置Awaited的简化版) - 注意:
infer只能在条件类型的“true 分支”中使用,且不能重复声明同名变量。
组合多个条件类型实现递归或模式匹配
复杂推导往往需要多层判断。常见模式是先用条件类型做初步分类,再递归处理或联合多个条件结果。
- 判断是否为数组并提取元素类型:
type ArrayElement<t> = T extends (infer U)[] ? U : T extends readonly (infer V)[] ? V : never;</t> - 扁平化嵌套数组类型(递归条件类型):
type Flatten<t> = T extends Array<infer u> ? Flatten<u> : T;</u></infer></t>
(TypeScript 4.1+ 支持递归条件类型,但需确保有终止条件,避免无限展开) - 联合类型中排除某个成员:
type Exclude<t u> = T extends U ? never : T;</t>—— 这就是内置Exclude的实现原理。
实用技巧与避坑点
写条件类型时容易忽略几个细节,导致推导失效或结果意外:
- 裸类型参数触发分布式行为是默认规则,不总是符合直觉;不确定时加方括号包装可强制非分布。
- 条件类型在类型别名中是惰性求值的,只有被实际引用时才解析;但在泛型约束或
extends检查中可能提前求值。 - 避免过度嵌套;超过三层嵌套建议拆分为多个辅助类型,提升可读性和错误提示质量。
- 用
type Test = MyType<string></string>配合 hover 查看 VS Code 推导结果,是最直接的调试方式。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











