typescript条件类型本质是编译期基于extends的类型兼容性判断,语法为t extends u ? a : b;支持分布式推导、泛型动态返回及api响应类型提取。

TypeScript 中的条件类型(Conditional Types)本质就是用三元表达式语法 T extends U ? X : Y 实现类型层面的“判断逻辑”,它不是运行时的三元运算,而是在编译期根据类型关系做静态推导。关键在于:它依赖 extends 的类型兼容性检查,而非值的真假。
条件类型的语法结构就是三元表达式
它的写法直接对应 JavaScript 三元表达式,但操作对象是类型:
-
T extends U ? A : B—— 若类型T能赋值给U(即T是U的子类型),则结果为A,否则为B - 这里的
extends是类型兼容性判断,比如stringextendsstring | number✅,但numberextendsstring❌ - 不涉及运行时值,所以不能写
value ? A : B;必须是纯类型参数间的逻辑
用泛型 + 条件类型实现动态类型返回
典型场景:根据输入类型自动推导输出类型。例如设计一个工具类型,把数组转为元素类型,非数组保持原类型:
type ArrayElementType<t> = T extends any[] ? T[number] : T;</t>
-
ArrayElementType<string></string>→string(因为string[]extendsany[]成立) -
ArrayElementType<number></number>→number(number不是数组,走 else 分支) - 配合泛型函数使用,就能让返回类型随参数类型“动态变化”
嵌套与分布式条件类型增强推导能力
当类型参数是联合类型时,TypeScript 默认会“分布式”地对每个成员分别计算条件类型:
type ToPromise<t> = T extends string ? Promise<t> : T extends number ? Promise<t> : never;</t></t></t>
-
ToPromise<string number></string>展开为ToPromise<string> | ToPromise<number></number></string>→Promise<string> | Promise<number></number></string> - 这种分布行为让条件类型能自然处理联合类型,无需手动
UnionToIntersection等技巧 - 若想禁用分布式行为,可用方括号包裹类型参数:
T extends any ? ... : ...→[T] extends [any] ? ... : ...
实际应用:从 API 响应中提取 data 或 error 类型
假设后端统一返回 { code: number; data?: T; error?: string },可定义安全取值类型:
type ApiResponse<t> = { code: number; data?: T; error?: string };<br>type SuccessData<t> = T extends ApiResponse<infer d> ? (T['code'] extends 0 ? D : never) : never;</infer></t></t>
- 先用
infer D提取出data的类型D - 再用
T['code'] extends 0模拟“code 为 0 时才有效”的业务逻辑(注意:这里只是类型模拟,实际code是值,但 TS 允许字面量类型参与 extends 判断) - 更健壮的做法是结合
Extract或ReturnType配合具体函数签名,避免过度依赖字面量类型约束











