几年前我准备 TypeScript 面试,把网上流传的那几十道“经典题”背得滚瓜烂熟:typeof 和 keyof 有什么区别、泛型约束怎么写、索引签名是什么……背的时候感觉自己什么都会,结果面试官让我现场手写一个 Omit<T, K>,我在白板上僵住了五分钟。最后靠着“把 K 从 keyof T 里排除”这句含糊的记忆,写了个当场报错的答案,回去翻文档才彻底搞明白。
那次之后我想通了一件事:TypeScript 的考题之所以让人痛苦,是因为大多数人把它们当成“知识点”在背,但本质上它们是“运算规则”。TypeScript 的类型系统不是一张死表格,它是一门能在类型层面上做查询、判断、分支、循环的小型语言。只要把这条逻辑线打通,所谓三大经典考题——类型查询、条件类型与推断、内置工具类型的实现——基本都可以现场推导出来,根本不用死记硬背。
这篇文章我就从这三道题切入,把背后的类型空间、运算规则和实战场景整个串一遍。适合正在备 TS 面试的人,也适合刚学完 TS 基础但一写类型就懵的开发者。
1. 背了五遍还是忘:先把类型空间当“一门小语言”来理解
1.1 一次面试翻车给我的真正教训
我后来复盘那次翻车,发现自己不是没背到,而是背的东西根本没有结构。我知道 Omit 的答案长什么样,但它为什么是 Pick<T, Exclude<keyof T, K>>,里面的 keyof、Exclude、Pick 分别负责哪一步,我完全形容不出来。就像背了一串咒语,换一个场景就彻底失效。比如面试官让我写一个“只保留类型前两个键”的变体,我直接懵住。
真正的问题不是记忆力,而是理解模型缺失。TypeScript 的类型系统里没有“API 列表”,只有一条条可组合的运算规则。你背得再熟,只要不知道规则怎么拼接,就永远只能回答原题,回答不了任何变形题。
1.2 值空间和类型空间:先分清两个世界
很多 TS 新手痛苦,是因为他们在用 JS 的思维理解 TS。JS 运行在值空间里,操作的是变量、对象、函数;TS 额外引入了一个类型空间,操作的是类型本身。这两个空间有各自的语法和操作符,而且部分操作符名字相同(比如 typeof),导致混淆。
我整理了一张对照表,把两个空间的核心操作并排放在一起,看完你就明白 TS 到底在“另一个世界”里干了什么:
| 你想做的事 | 值空间(JS 运行时) | 类型空间(TS 编译
