TypeScript 7:当编译器不再是 JavaScript
2026 年 7 月 8 日,tsc 这个命令在十多年后第一次不再运行 JavaScript。
TypeScript 7.0 的编译器用 Go 重写,微软给出的真实代码库基准是 8 到 12 倍的全量构建提速。
但这次升级和以往任何一次都不同:语言没变,工具链却断了一截。
这篇文章不复述发布公告,而是回答三个更实际的问题:那些倍数是怎么来的、 为什么大量工具现在还不能升到 7、以及你的项目应该按什么顺序动。
先看数字,再看数字的上下文
微软公布的基准用的是公开代码库,而非合成测试,这点值得肯定。原始数据大致如下:
| 代码库 | TS 6.0 | TS 7.0 | 提升 |
|---|---|---|---|
| VS Code(全量类型检查) | 125.7 s | 10.6 s | 约 11.9× |
| Sentry | 139.8 s | 15.7 s | 约 8.9× |
| Playwright | 12.8 s | 1.47 s | 约 8.7× |
| VS Code 编辑器报错首现 | 约 17.5 s | < 1.3 s | 约 13× |
这些数字是真的,但有几个前提需要说清楚,否则容易期待落空:
- 提升幅度和项目规模正相关。 小项目本来就只花几百毫秒,压缩到几十毫秒在体感上几乎没有差别。 收益最大的是"全量检查要等一分钟以上"的中大型 monorepo。
- 这是全量(clean build)数据。 日常增量编译和 watch 模式本来就有缓存,改善幅度通常小于全量构建。
- 并行度相关。 7.0 把解析、检查、产物生成拆到多线程,核心数少的机器拿到的增益主要来自"原生代码本身更快"这部分,而不是并行。
微软同时提到内存占用下降约 18%(VS Code 从 5.2 GB 降到 4.2 GB)。 对 CI 机器来说这个变化可能比速度更有价值 —— 它直接决定你能在同样规格的 runner 上跑多少个并行任务。
Go 为什么能快一个数量级
原因不是"Go 比 JavaScript 快十倍"这么简单的比较。真正的来源有三块:
1. 没有 JIT 预热与 GC 压力
原实现跑在 Node.js 上,冷启动要先解析、编译、预热几十万行 JavaScript。 这是为什么"打开一个文件要等十几秒"——大部分时间不在类型检查,而在让运行时热起来。 Go 编译成原生二进制,启动即全速。
2. 真正的共享内存多线程
Node.js 的单线程模型决定了原编译器只能靠 worker 进程做粗粒度并行,进程间传数据要序列化。 7.0 使用共享内存的多线程,类型检查可以按项目切分到多个 worker:
# 每个项目 8 个 checker worker npx tsc --checkers 8 --noEmit -p tsconfig.json # 多项目构建:4 个项目并行,每个项目 4 个 checker(最多 16 个) npx tsc --build --builders 4 --checkers 4 # 单线程模式:用于排查顺序相关的诡异结果 npx tsc --singleThreaded --noEmit -p tsconfig.json
这三个参数在 7.0 中标注为实验性。--checkers 默认是 4;
调高会占用更多内存,且在极少数情况下可能出现"顺序相关"的结果差异 ——
所以官方保留了 --singleThreaded 作为排查手段。
3. 移植而非重写
这是最关键的一点。团队没有借机重新设计类型系统,而是把原有逻辑逐段翻译成 Go,
目标是与 6.0 的类型检查行为保持一致。内部代号 Strada(旧 JS 代码库)与 Corsa(新 Go 代码库),
两者刻意保留的差异记录在一个 CHANGES.md 文件里。
对你的意义是:升级不会让原本通过的类型检查突然失败(除了配置项被移除的情况)。 这是一个罕见的、语言语义完全不变的性能升级。
真正的麻烦:7.0 没有 compiler API
7.0 最容易被忽略、影响却最大的事实是:它不提供对外编程接口。 新的 API 预计在 7.1 提供。
这意味着所有"以库的形式调用 TypeScript"的工具都无法运行在 7.0 上:
| 工具类别 | 代表 | 7.0 状态 |
|---|---|---|
| Lint / 静态检查 | typescript-eslint | 需留在 6.0 |
| 框架模板检查 | Vue、Svelte、Astro、Angular | 需留在 6.0 |
| 代码生成 / 转换 | ts-morph 及各类 codemod | 需留在 6.0 |
| 纯命令行编译 | tsc 本身 |
可直接使用 7.0 |
于是出现了一个很容易踩的坑:从 2026 年 7 月起,npm 上 typescript 的
latest 标签已经指向 7.x。执行
npm i -D typescript 装到的是原生编译器,
而如果你的 lint 流程依赖 API,它会在这一步突然坏掉。想留在 6.0 必须显式指定:
# 锁定 6.x npm i -D typescript@6 # 或者并列安装:让 lint 用 6,构建用 7 npm i -D typescript@7 @typescript/typescript6 # 验证实际生效的编译器版本(重要) npx tsc --version
@typescript/typescript6 会带一个名为 tsc 的二进制,
与 typescript@7 的同名二进制冲突。
npm 会把后写入的那个链到 node_modules/.bin,
结果可能是你以为装了 7,实际跑的还是 6。
所以上面最后一行不是可选项:每次安装后都打印一次版本, 确认 CI 里跑的到底是哪个编译器。
被移除的配置项
6.0 里所有标记弃用的选项,在 7.0 中变成硬错误。这不是提醒,是直接编译失败。 受影响的常见项:
target: "es5"baseUrl作为模块查找根目录moduleResolution: "node"/"node10"- AMD、UMD、SystemJS 三种模块格式
另外 6.0 改了若干默认值,这些即使你不改 tsconfig 也会生效,
是升级时"报错最多"的来源:
| 选项 | 旧默认 | 6.0 起的默认 |
|---|---|---|
strict | false | true |
module | 随 target 变化 | esnext |
target | es5 | 最新 ES 版本 |
types | 所有 @types 包 | 空数组 |
noUncheckedSideEffectImports | false | true |
其中 types 默认为空数组最容易造成困惑:@types/node、
@types/jest 不再被自动引入,症状是一堆 Cannot find name 'process'、
Cannot find name 'describe'。解决方式是显式声明:
{
"compilerOptions": {
"target": "es2024",
"module": "esnext",
"moduleResolution": "bundler",
"strict": true,
"verbatimModuleSyntax": true,
// 6.0 起必须显式列出,否则不加载
"types": ["node", "vitest/globals"]
}
}
推荐的迁移顺序
把 6.0 当成"清场版本"用,是风险最低的路径。分四步:
第一步:先上 6.0,把所有弃用项清掉
这一步不追求变快,追求的是 tsc --noEmit 在没有
"ignoreDeprecations": "6.0" 兜底的情况下零报错。
在 6.0 上有兜底选项可用,到了 7.0 就没有了。
第二步:CI 里并行跑 6 和 7
构建用 7 计时,lint 仍走 6。两边都绿,再考虑切换。这样能提前发现 "行为差异"与"工具缺失"两类问题:
jobs:
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 原生编译器(计时用)
run: |
npx -y typescript@7 tsc --noEmit -p tsconfig.json
npx -y typescript@7 tsc --version
- name: 6.0 + API 工具(lint 用)
run: |
npm ci
npx tsc --version
npm run lint
第三步:确认工具链的 7.1 支持情况
关注三类工具:lint、框架模板检查、基于 API 的代码生成。 它们不支持 7.x 之前,不要动 CI 的主编译路径。
第四步:全量切换,回收 CI 时间
等到 API 到位、工具跟进,再把默认编译器换成 7。 真正的收益此刻才兑现 —— 尤其是那些因为"全量检查太慢"而只跑增量、把问题留到合并后才发现的项目。
这次升级该怎么看
TypeScript 7 是一次罕见的"纯性能"升级:类型语义不变,语言不变,改的只是引擎。 对长期忍受大 monorepo 编译等待的团队,这是数年来最实在的一次改善。
但它同时暴露了一件事:TypeScript 早已不只是编译器,而是一套被大量工具依赖的基础设施。 换引擎意味着这些工具需要一个稳定的接口才能跟上,而接口比引擎慢了一拍。 这不是微软的失误,而是生态型项目升级时的结构性代价。
判断要不要现在升,只需回答一个问题:你的构建流程里,有多少环节是以库的形式调用 TypeScript,
而不是调用 tsc 命令?如果是零,现在就能升;如果不是,先清配置,等 7.1。
- TypeScript 6.0 升级说明与发布时间线(含 6.0 默认值变更、弃用项清单)
- TypeScript 7.0 发布公告与 Project Corsa 基准数据(VS Code / Sentry / Playwright 构建耗时、内存变化)
- TypeScript 7 迁移实践指南(
--checkers、--builders、tsc6包与二进制冲突说明) - 生态影响分析(
typescript-eslint、Vue、Svelte、Astro、Angular 对 compiler API 的依赖)