typescript条件类型通过t extends u ? x : y在编译时基于结构兼容性做分支判断,支持分布式分发、infer提取及嵌套组合,是构建高精度工具类型的核心机制。

TypeScript 中的条件类型通过 T extends U ? X : Y 语法,在编译时根据类型兼容性做分支判断,实现真正意义上的“类型层面 if-else”。它不运行代码,而是让编译器基于结构关系推导出新类型,是构建高精度工具类型的核心机制。
基础写法:用 extends 做类型关系判断
条件类型的本质是检查左侧类型能否赋值给右侧类型(即是否满足结构兼容)。只要满足,就取问号后的类型;否则取冒号后的类型。
-
判断是否为字符串字面量:
type IsHello<t> = T extends 'hello' ? true : false;</t>——IsHello得true,IsHello得false -
过滤函数类型:
type NonFunction<t> = T extends Function ? never : T;</t>—— 对string | number | () => void应用后,函数部分被替换为never,最终剩下string | number -
区分基本类型与对象:
type PrimitiveOrObject<t> = T extends string | number | boolean | null | undefined ? 'primitive' : 'object';</t>
联合类型自动分发:分布式行为是关键特性
当泛型参数是裸联合类型(如 A | B)时,条件类型会自动拆开对每个成员分别计算,再合并结果。这是默认行为,也是很多工具类型生效的前提。
-
type ToArray<t> = T extends any ? T[] : never;</t>ToArray<string number></string>不是(string | number)[],而是string[] | number[] - 想禁用分发?把类型包一层:
[T] extends [U] ? X : Y或{ t: T } extends { t: U } ? X : Y - 内置
Exclude<t u></t>就依赖此行为:遍历T每个成员,若能赋值给U就变never,否则保留
结合 infer 提取结构内部类型
infer 必须出现在 extends 左侧的类型模式中,用于“捕获”某一部分结构的类型,常用于解构函数、数组、Promise 等。
-
提取函数返回值:
type MyReturnType<t> = T extends (...args: any) => infer R ? R : any;</t>MyReturnType string>→string -
提取数组元素类型:
type ElementType<t> = T extends Array<infer e> ? E : T;</infer></t>ElementType<number></number>→number[](只解一层) -
解包 Promise:
type Awaited<t> = T extends Promise<infer u> ? U : T;</infer></t>Awaited<promise>></promise>→string
嵌套与实用组合:构建真实可用的工具
多个条件可嵌套使用,配合 never 排除、交叉/联合组合,就能逼近运行时逻辑的类型表达。
-
根据输入类型决定返回类型:
type Process<t> = T extends string ? number : T extends number ? string : boolean;</t> -
排除 null 和 undefined:
type NonNullable<t> = T extends null | undefined ? never : T;</t> -
只保留对象类型(非原始值):
type ObjectOnly<t> = T extends object ? (T extends Function ? never : T) : never;</t> - 实际项目中优先复用内置类型(
ReturnType、Parameters、InstanceType等),它们底层就是这类模式











