TypeScript的高级类型是区分初学者和进阶开发者的分水岭。基础类型只能描述简单的数据结构,而高级类型可以表达复杂的类型关系,实现类型层面的逻辑运算。这篇文章把常用的高级类型逐一拆解,并结合实际开发中容易混淆的问题给出分析。

联合类型与交叉类型的本质区别
联合类型和交叉类型是两组最容易混淆的符号。|表示联合,含义是“或”,即变量可以是其中任意一种类型;&表示交叉,含义是“与”,即必须同时满足所有类型的约束。
很多人以为交叉类型就是取交集,这个理解不完全准确。对于对象类型来说,交叉更像是“合并”,把多个类型的属性叠加到一起。而对于字面量类型的交叉,结果往往是never,因为一个值不可能同时是两个不同的字面量:
type A = { name: string };
type B = { age: number };
type C = A & B; // 同时拥有 name 和 age
type L = 'a' & 'b'; // never,不存在这样的值联合类型还有一个重要特性叫“分发”。当泛型参数是联合类型并被用在条件类型中时,条件类型会自动对每个成员分别计算,最后再把结果合并成联合类型。理解这一点是掌握条件类型的关键。
泛型与条件类型的进阶用法
泛型的核心作用是让类型变成“参数”,从而在类型层面复用逻辑。但很多开发者只停留在函数泛型的层面,实际上泛型约束、默认值、以及和条件类型配合才是真正的威力所在。
keyof和typeof是两个重要的类型运算符。keyof T获取某个类型的所有属性名组成的联合类型,typeof则可以从一个运行时的值反向推导出类型,这在给配置对象定义类型时特别实用。
条件类型的语法是T extends U ? X : Y,配合infer关键字可以在匹配的过程中“提取”出某个类型。比如内置的ReturnType就是用infer拿到函数的返回值类型:
type MyReturnType<T> =
T extends (...args: any[]) => infer R ? R : never;
function getUser() {
return { id: 1, name: '张三' };
}
type User = MyReturnType<typeof getUser>; // { id: number; name: string }再比如提取Promise内部的类型,也是同样的套路,用infer声明一个位置,让TypeScript自己去推断填充。掌握了infer,你会发现很多原来需要手动声明的类型都能自动推导出来。
需要注意的是,如果不想让条件类型发生分发,可以用方括号把T包起来:[T] extends [U] ? X : Y,这样即使传入联合类型也会作为整体参与判断,这在判断never时尤其重要,因为裸的never分发后结果是never,永远走不到任何分支。
映射类型与内置工具类型的实现原理
TypeScript内置了一批工具类型,比如Partial、Readonly、Pick、Record。它们的底层都是映射类型,语法是在方括号里用in遍历一个联合类型:
type MyPartial<T> = {
[K in keyof T]?: T[K];
};
type MyReadonly<T> = {
readonly [K in keyof T]: T[K];
};
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};映射过程中还可以加修饰符的加减操作。TypeScript 4.1之后支持-readonly、-?这样的语法,用来移除只读或可选标记。官方的Mutable类型就是这么实现的。
模板字面量类型也是映射类型的黄金搭档。配合infer和递归,可以实现诸如把下划线命名转驼峰、给对象的所有方法加上统一前后缀这类需求,这在编写类型安全的工具库时非常实用。
any、unknown与never的使用边界
这三个顶层和底层类型经常被混用。any会直接放弃类型检查,等于回到了JavaScript;unknown同样可以承接任意值,但使用前必须先收窄类型,因此是更安全的选择;never表示不存在的类型,常用于穷尽检查和表示永远不会返回的函数。
一个实用的技巧是在switch语句中利用never做穷尽校验。给default分支的变量赋值为never类型,一旦后续给枚举新增了成员而忘记处理,编译器会立刻报错,避免运行时遗漏分支。
type Shape = 'circle' | 'square';
function area(s: Shape) {
switch (s) {
case 'circle': return 1;
case 'square': return 2;
default:
const _check: never = s; // 如果Shape新增成员,这里会报错
return _check;
}
}总结一下学习路径:先把联合、交叉、泛型约束这些基础打牢,再攻克条件类型和infer,最后研究映射类型和模板字面量类型的组合运用。高级类型写多了你会发现,类型系统本身就是一门小型的函数式编程语言,掌握它的思维方式,比背下所有工具类型的用法重要得多。
TypeScript高级类型泛型修改时间:2026-09-11 15:36:32