我今天等构建结束,等了整整四十五秒。
我盯着那个不停转的转圈圈,思路断了。手机刷了两眼,等终端终于变绿,我已经忘了自己刚才到底在测什么。
我们一直把“编译慢”当成类型安全的门票,默认两百万行代码要检查,慢点很正常。
但 TypeScript 团队不这么想。
过去一年,微软一直在悄悄做一场超大规模的架构重构,代号 Project Corsa。这不是新语法糖,也不是新的严格模式,更不是“再加几个 flag 就完事”。这是一场对编译器本体的外科手术,目的是拆开并重构那颗已经运行了十年的核心引擎。
他们正在把支撑 TypeScript 十年的那套核心逻辑拆分、解耦、重塑。
如果你觉得 TypeScript 5 已经够快了,那你可能还没准备好迎接接下来的变化。这是一个关于团队如何拆掉“巨石应用”,从内部拯救我们于大型代码库构建效率的故事。
1. 五万行代码的巨石问题
想搞懂 Project Corsa,你得先认识一个躲在 node_modules 里的“怪物”。
问题是什么: 很多年里,TypeScript 的核心逻辑——也就是“判断一个字符串到底是不是字符串”的那部分——几乎都塞在一个文件里:checker.ts。
它膨胀到了 5 万行以上。更要命的是,它还大量使用内部 Namespaces(一种已经过时的 TypeScript 组织方式),而不是现代的 ES Modules。
后果是什么: 像 V8 这种现代 JavaScript 引擎(Node.js 和 Chrome 背后那位)并不擅长优化“巨型 namespace”。当所有东西都被裹进同一个全局作用域,热路径很难被单独优化,也很难真正做到 tree-shaking 或精细加载。你以为你在跑一个编译器,其实你在拖着一锅“全局命名空间浓汤”运行。
可视化架构(巨石时代):
[ THE OLD COMPILER ]
+--------------------------------------------------+
| namespace ts { |
| checker.ts (50k lines) |
| parser.ts |
| binder.ts |
| // 所有模块共享可变的全局状态 |
| } |
+--------------------------------------------------+
Result: 高内存占用,难以优化
Corsa 的解法: 把这块巨石拆开,迁移为标准的 ECMAScript Modules,逐步告别 namespace ts 的老路。
这样做的意义很直白:引擎可以只加载需要的部分;V8 也终于能把关键函数“拎出来单独优化”,不再让它们埋在一锅全局变量里喘不过气。
2. 单态(Monomorphism):对象“长相一致”的速度秘密
这是最深的技术改动,也是最能带来性能收益的地方。
概念: JavaScript 引擎最开心的时候,是对象永远“长得一样”。这叫 单态(Monomorphism)。
当一个函数一直接收同一种形状的对象,引擎就能大胆进行优化;可一旦下一次你传进来的对象突然多了个“隐藏属性”,引擎就会犹豫、撤回优化,变成 多态(Polymorphic),性能直接滑进“慢模式”。
旧问题: 老的 TypeScript 编译器在 check 阶段会动态修改对象:跑着跑着就给 AST 节点临时加字段、挂属性。对业务逻辑来说,这叫“方便”;对 JIT 编译器来说,这叫“你在搞我”。结果就是:优化频繁失效,性能被迫保守。
变化: Project Corsa 强制对象形状稳定,不再运行时随手乱改。
基准代码(概念示意):
// 旧编译器(多态 / 更慢)
function checkNode(node: any) {
// 运行中临时加属性,会直接拖垮性能
if (needsCheck) {
node.checkFlag = true;
}
}
// Corsa 架构(单态 / 更快)
interface Node {
readonly flags: number; // 一次定义,形状固定不再变化
}
function checkNode(node: Node) {
// 用位掩码替代对象的动态变更
const isChecked = node.flags & CheckFlags.Checked;
}
结果: 当对象形状保持稳定,编译器能更接近“贴着硬件跑”的状态。TypeScript 仓库的早期基准数据显示,仅靠这些内部重构,编译速度就可能提升 10% 到 25%。
不是你写得更少了,是编译器终于不再被自己的老习惯拖累。对于寻求极致性能的前端工程化方案,这无疑是个重磅利好。
3. 彻底解耦:把类型检查器“拆出来”
以前的版本里,Parser(语法解析) 和 Checker(类型验证) 绑得太紧。
痛点在哪: IDE(比如 VS Code)的体验最受影响。你敲一个字符,IDE 第一时间想知道的是:“语法是不是还成立?”它此刻根本不需要完整的类型推导。但旧架构常常把 Checker 也拖上车处理——于是你想要的即时反馈,变成了“顺便做一次重型体检”。
架构转向: Corsa 把边界划得更清楚,职责拆得更干净。
[ SOURCE CODE ]
|
V
[ PARSER ] --(AST)--> [ BINDER ] --(Symbols)--> [ CHECKER ]
(快) (中等) (重)
影响是什么:
- 语法高亮会更“秒回”。
- 自动补全能更早出现——甚至在类型错误还没算完之前。
- 构建更轻:只需要“剥掉类型”的工具(比如 esbuild、swc)能参考更清晰的实现边界,不必被一整坨 checker 牵连。
4. 这对你的应用意味着什么?
好消息是:你不需要重写任何业务代码就能吃到 Corsa 带来的红利。这才是它最吸引人的部分——你坐着不动,编译器自我进化。
但你也确实需要提前检查一下项目所依赖的“基础设施”。
变化点: TypeScript 正在转向纯 ES Modules,这意味着扩展编译器的方式会随之改变。如果你写过自定义的 AST Transformer 或 ESLint 规则,或者用过依赖 ts 内部 namespace 的工具链,那些东西可能会迎来一波适配挑战。
警告: 依赖 ts.internal 等非公开内部 API 的老工具或插件,在 TypeScript 7 时代很可能直接无法工作。
行动建议: 去检查一眼你的 package.json 和构建配置,看看有没有对编译器内部实现的深度依赖。
- 相对安全: 常规构建工具链(如 Vite、Webpack、Angular CLI)。这些主流工具通常会及时跟进官方变化。
- 相对高风险: 自己编写的 AST transformer、年代久远的自定义 lint 插件、或任何“硬钩内部结构”的私有脚本。
5. 下一步行动
这场变化的本质,是 TypeScript 编译器正在从一个“能跑就行的巨型脚本”,成长为一个符合现代软件工程标准的成熟项目。
你现在能做的一件有对比意义的小事是:
去你的项目终端,运行:
npx tsc --extendedDiagnostics
找到输出结果里的 “Check time(检查耗时)” ,把它记下来。
等 TypeScript 7 正式发布后,在同样的项目上再跑一次这个命令。你会直观地看到 Project Corsa 带来的性能差异——这不是玄学优化,而是在你每一次保存文件、每一次触发构建、每一次无奈等待时,实打实减少的那几十秒。理解这类底层优化原理,也是深入计算机基础知识的一部分。
本文由 云栈社区 整理分享,关注编译器技术与前端工程化演进。