条件类型,听名字就有点像是在类型系统里写if-else。没错,它的核心思想就是这样:根据一个类型关系检查,在编译时动态选择两种可能的类型之一。这玩意儿是TypeScript类型编程里真正的“分水岭”,一旦掌握,你就能写出像魔法一样灵活和强大的类型工具。
![图片[1]-什么是条件类型?-速码派](http://www.sumapai.com/wp-content/uploads/2026/01/16d292a7ea594d9aa4ad6ca6562a2da9_tplv-tb4s082cfz-aigc_resize_1080_1080-1024x683.webp)
最基本的语法长这样:T extends U ? X : Y。你把它读作:“如果类型T可以赋值给类型U,那么结果类型就是X,否则就是Y。” 它有点像三元表达式,但操作的对象是类型,发生在编译阶段。
举个最直观的例子,你想写一个类型,它能提取出数组元素的类型:
type ElementType<T> = T extends (infer U)[] ? U : T;
这个ElementType就是一个条件类型。它检查T是否扩展自某个U类型的数组。如果是,它就“推断”(infer)出数组元素的类型U并返回;如果不是,就直接返回T本身。试试看:
type A = ElementType<string[]>; // A 是 string
type B = ElementType<number>; // B 是 number
看到infer了吗?它是条件类型里的关键字,专门用来在extends的约束中声明一个待推断的类型变量。它让条件类型从单纯的“检查”升级到了可以“提取”或“解包”结构。
条件类型真正发挥威力的地方,是和泛型结合,用来构建高级工具类型。TypeScript内置的很多实用类型,比如Exclude, Extract, NonNullable,底层都是条件类型。咱们可以看看Exclude大概是怎么工作的:
type MyExclude<T, U> = T extends U ? never : T;
MyExclude<string | number | boolean, number>这个运算,会发生一个叫“分布式条件类型”的神奇效果。它不是把T作为一个整体string | number | boolean去判断,而是会拆开,变成三个独立的判断:
string extends number ? never : string=> 得到stringnumber extends number ? never : number=> 得到neverboolean extends number ? never : boolean=> 得到boolean
最后再把结果联合起来:string | never | boolean,而never在联合类型中会被忽略,所以最终类型就是string | boolean。这就实现了从联合类型中排除指定成员。
这个“分布式”特性只在T是“裸类型参数”(即T本身,没有被包裹在数组、函数等结构中)且出现在extends左侧时才会触发。理解这点很重要,它是你掌控条件类型行为的关键。
刚开始玩条件类型可能会觉得绕,我的建议是从模仿内置工具类型开始。试着写写自己的MyExtract、MyReturnType。当你需要根据输入类型的某些特征,来推导出与之精确匹配的输出类型时,条件类型几乎是你唯一的选择。它让类型系统从静态描述,变成了可以编程的动态逻辑。


























暂无评论内容