avatar
转载2026/07/10

TypeScript 7.0:进入原生编译器时代

AI 总结

TypeScript 7.0 将编译器和语言服务移植到 Go,带来 8 到 12 倍的构建速度提升、并行类型检查和更快的编辑器体验,同时介绍与 TypeScript 6 并行使用、配置迁移以及生态兼容性。

TypeScript 7.0 发布了。

这次升级并不是普通意义上的版本迭代。TypeScript 团队将编译器和语言服务重新实现为原生的 Go 程序,在尽可能保持行为兼容的前提下,换掉了原来的运行时基础设施。

官方在真实项目上的测试结果显示,完整构建通常可以获得 8 到 12 倍 的速度提升。对于大型 monorepo 来说,这意味着类型检查不再是一件需要交给 CI、然后等待几分钟才能得到反馈的事情。

这篇文章介绍 TypeScript 7.0 做了什么、它为什么会变快,以及升级时需要注意哪些问题。

TypeScript 为什么需要重写

TypeScript 的核心体验并不只发生在执行 tsc 的那一刻。日常开发中,下面这些操作都依赖 TypeScript:

  • 编辑器首次加载项目
  • 输入代码时的自动补全
  • 实时诊断和错误提示
  • 查找所有引用
  • 重命名符号
  • --watch 模式下的增量检查
  • CI 中的完整类型检查

项目规模较小时,编译器实现上的差异不容易被感知。但当项目拥有数千个文件、复杂的项目引用和庞大的依赖图时,解析、类型检查和语言服务都会变成明显的性能瓶颈。

TypeScript 7.0 的目标不是只让某一条命令更快,而是缩短整个反馈链路:

编辑文件
  │
  ├── 更快看到诊断结果
  ├── 更快获得自动补全
  ├── 更快完成查找引用
  └── 更快完成构建和类型检查

用 Go 重写后的 TypeScript

TypeScript 7.0 是 TypeScript 编译器的原生移植版本,新的代码库使用 Go 实现。移植过程中,团队尽量保留了原有编译器的结构和逻辑,重点改变的是执行方式:

  • 使用原生代码执行,减少 JavaScript 运行时开销
  • 利用共享内存,降低不同工作进程之间的数据复制成本
  • 对解析、类型检查和输出等阶段进行并行化
  • 使用更适合跨平台的文件监听实现

这不是把 tsc 简单地打包成一个更大的二进制文件。TypeScript 7.0 同时重建了语言服务和 watch 模式,因此性能改进也会出现在编辑器中。

官方给出的一个例子是:在 VS Code 代码库中,打开一个存在错误的文件后,首次看到错误的时间从大约 17.5 秒降到了 1.3 秒以内。

并行化:--checkers 与 --builders

TypeScript 7.0 会自动使用多线程执行许多任务。解析和输出通常可以独立处理,因此并行化比较直接;类型检查和项目引用构建则存在更多依赖关系,需要更谨慎地调度。

并行类型检查

类型检查器默认使用 4 个 worker。可以通过 --checkers 调整数量:

npx tsc --checkers 8

增加 worker 数量通常可以进一步缩短大型项目的构建时间,但会消耗更多内存。CI 机器的 CPU 和内存比较有限时,也可以主动降低数量:

npx tsc --checkers 1

--checkers 1 可以近似看作单线程类型检查。

需要注意的是,类型检查过程中存在一些依赖顺序的操作。不同的 checker 数量在极少数情况下可能暴露依赖顺序问题。因此,团队最好在本地和 CI 中固定同一个 --checkers 值,避免不同环境得到不同的结果。

并行项目构建

使用项目引用的 monorepo 可以通过 --builders 控制同时构建的项目数量:

npx tsc --build --builders 4

--builders 和 --checkers 会产生乘法效应。例如:

--builders 4 × --checkers 4 = 最多 16 个类型检查器

因此不能简单地把两个参数都调到最大。并发数量越高,构建速度不一定线性增长,内存压力却会明显增加。建议先测量当前项目,再根据构建时间和峰值内存选择合适的组合。

单线程模式

调试编译器行为、对比 TypeScript 6 和 7,或者运行在资源非常有限的环境中时,可以关闭并行化:

npx tsc --singleThreaded

这个选项会让解析、类型检查和输出都以单线程方式运行。

更可靠的 --watch

TypeScript 7.0 重建了 --watch 模式,底层文件监听实现来自 Parcel watcher 的 Go 移植版本。

传统的轮询方式需要定期扫描文件和依赖目录。项目越大、node_modules 越复杂,轮询的计算成本就越高。新的 watcher 针对不同平台使用更高效的文件系统事件机制,并且避免让 TypeScript 引入完整的 C++ 构建工具链。

对于前端项目来说,这会直接改善保存文件后的体验:

npx tsc --watch

它不仅是一次性的构建更快,而是让“修改代码 → 等待检查 → 继续修改”的循环变短。

与 TypeScript 6 并行使用

TypeScript 7.0 发布后,生态并不会立刻全部迁移。部分工具需要直接调用 TypeScript 的 API,而 7.0 暂时还没有稳定的 API。官方预计在 TypeScript 7.1 提供新的 API,因此过渡期需要让 TypeScript 6 和 7 共存。

官方提供了 @typescript/typescript6 兼容包。它会提供 tsc6 命令,同时重新导出 TypeScript 6.0 的 API。

如果某个工具仍然依赖 TypeScript 6,可以使用 npm alias:

npm install -D typescript@npm:@typescript/typescript6

对应的 package.json 可以写成:

{
  "devDependencies": {
    "typescript": "npm:@typescript/typescript6@^6.0.2"
  }
}

这样项目中会得到 tsc6,但默认的 tsc 也会随之指向兼容包。如果希望同时使用两个版本,可以分别配置 alias:

{
  "devDependencies": {
    "@typescript/native": "npm:typescript@^7.0.2",
    "typescript": "npm:@typescript/typescript6@^6.0.2"
  }
}

这里的思路是:业务工具继续通过 typescript 读取 6.0 API,而开发者通过 @typescript/native 使用 7.0 的编译器。具体命令和包管理器行为仍然应该在项目中实际验证。

Nightly 版本的变化

之前 TypeScript 7 的 nightly 版本主要通过 @typescript/native-preview 发布。现在正式版本已经发布,后续 nightly 构建会逐步回到标准的 typescript 包,并使用 next tag:

npm install -D typescript@next

正式升级则使用普通的安装方式:

npm install -D typescript

从 TypeScript 6 迁移到 7

TypeScript 7.0 的类型检查和命令行行为主要以 TypeScript 6.0 为兼容基线。理论上,开启 stableTypeOrdering 且没有依赖 ignoreDeprecations 的项目,大部分代码都可以保持相同的检查结果。

不过,TypeScript 7.0 会继承 TypeScript 6.0 的新默认值,并把之前已经废弃的配置和语法变成硬错误。

重要的默认配置

以下配置需要特别留意:

  • strict 默认值变为 true
  • module 默认值变为 esnext
  • target 默认使用紧邻 esnext 之前的稳定 ECMAScript 版本
  • noUncheckedSideEffectImports 默认值变为 true
  • libReplacement 默认值变为 false
  • stableTypeOrdering 默认值变为 true,并且不能关闭
  • rootDir 默认值变为项目根目录 ./
  • types 默认值变为 []

其中,rootDir 和 types 是最容易影响现有项目的两个变化。

如果项目源码在 src 目录中,而 tsconfig.json 位于项目根目录,可以显式设置 rootDir:

{
  "compilerOptions": {
    "rootDir": "./src"
  },
  "include": ["./src"]
}

如果项目依赖 Node.js、Jest 或其他全局类型声明,则应该显式声明它们:

{
  "compilerOptions": {
    "types": ["node", "jest"]
  }
}

不再支持的配置

下面这些旧配置在 TypeScript 7.0 中不再支持:

  • target: es5
  • downlevelIteration
  • moduleResolution: node 或 node10
  • moduleResolution: classic
  • module: amd、umd、systemjs、none
  • baseUrl
  • 将 esModuleInterop 或 allowSyntheticDefaultImports 设置为 false
  • 将 alwaysStrict 设置为 false

模块解析建议迁移到 bundler 或 nodenext,模块格式则根据项目使用 esnext 或 preserve。

例如,过去依赖 baseUrl 的路径配置,可以改为相对于项目根目录的路径映射:

{
  "compilerOptions": {
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

不要把升级 TypeScript 和修改所有构建工具配置混在一个提交中。更稳妥的方式是先升级编译器,再根据错误信息逐项修复配置,最后单独验证打包、测试和编辑器行为。

Template Literal Types 的 Unicode 变化

TypeScript 7.0 修正了模板字面量类型对 Unicode 字符的处理方式。

以前,模板字面量类型在推断字符串时更接近 JavaScript 的 UTF-16 code unit 行为。一个 emoji 可能会被拆成两个 surrogate,导致类型中出现没有实际语义的字符串片段。

现在它会按照 Unicode code point 处理:

 type HeadTail<S> = S extends `${infer Head}${infer Tail}`
   ? [Head, Tail]
   : never
 
type Result = HeadTail<'😀abc'>
// TypeScript 7.0: ['😀', 'abc']

这会影响那些明确模拟 UTF-16 code unit 长度或索引行为的类型工具。不过对于绝大多数字符串操作来说,新行为更符合开发者直觉,也更接近 for...of 或展开字符串时的结果。

JavaScript 文件的类型检查变化

TypeScript 长期以来通过 JSDoc 和一些特殊代码模式支持 .js 文件。TypeScript 7.0 对这部分逻辑进行了重构,使 JavaScript 文件的分析方式更接近 TypeScript 文件。

可能影响现有 JavaScript 项目的变化包括:

  • 类型位置不能直接使用值,需要使用 typeof someValue
  • @enum 不再作为特殊结构处理,应改用 @typedef
  • 单独的 ? 不再表示类型,应改用 any
  • @class 不再把函数自动视为构造函数,应使用真正的 class
  • 不再支持后缀 !
  • 类型名需要定义在 @typedef 标签内部
  • 不再支持 Closure 风格的函数类型写法

如果项目使用 checkJs 或大量 JSDoc,升级前应该单独运行一次 TypeScript 7 的检查,不要只在 TypeScript 源码项目上验证。

编辑器和框架生态

TypeScript 7.0 的语言服务基于新的 Language Server Protocol 实现,并支持多线程处理编辑器请求。自动导入、可展开 hover、inlay hints、code lens、跳转到源定义、JSX linked editing 等能力已经补齐,语义高亮和导入整理等功能也在持续完善。

VS Code 用户可以安装 TypeScript 7 专用扩展,并通过命令面板在两个语言服务器之间切换:

  • Enable TypeScript 7 Language Server
  • Disable TypeScript 7 Language Server

但需要注意,Vue、MDX、Astro、Svelte 等嵌入式语言工作流暂时可能无法直接使用 TypeScript 7。原因是这类工具会把 TypeScript 嵌入自己的编译器或语言服务中,而 TypeScript 7 目前还没有稳定的程序化 API。

因此,比较现实的迁移策略是:

  1. 在 CI 中先使用 TypeScript 7 执行完整类型检查。
  2. 对不依赖语言服务插件的纯 TypeScript 项目启用 TypeScript 7。
  3. Vue、MDX 等项目暂时保留 TypeScript 6 的编辑器支持。
  4. 等相关生态完成 API 迁移后,再统一切换语言服务器。

应该现在升级吗

如果项目是纯 TypeScript、主要使用 tsc 进行类型检查,并且规模较大,那么 TypeScript 7.0 值得尽早在 CI 和本地分支中测试。构建时间和编辑器反馈速度的提升,可能会直接改变开发体验。

如果项目依赖以下能力,则建议先做兼容性评估:

  • 直接调用 TypeScript API 的工具
  • typescript-eslint 等编译器集成工具
  • Vue、MDX、Astro、Svelte 等嵌入式语言插件
  • 依赖旧模块格式或 baseUrl 的构建配置
  • 大量使用 JSDoc 的 JavaScript 项目

一个比较安全的升级流程是:

复制当前 lockfile
    │
    ▼
安装 TypeScript 7
    │
    ▼
运行 tsc --noEmit
    │
    ├── 修复 tsconfig 默认值带来的错误
    ├── 修复已移除的配置项
    └── 检查 JavaScript / JSDoc 项目
    │
    ▼
运行单元测试、打包和 lint
    │
    ▼
验证编辑器插件和 monorepo 构建

总结

TypeScript 7.0 最重要的变化不是增加了多少个新的类型语法,而是重新定义了 TypeScript 工具链的性能上限:

  • 编译器和语言服务迁移到 Go 原生实现
  • 完整构建通常获得 8 到 12 倍速度提升
  • 类型检查和项目引用构建支持并行化
  • --watch 使用新的跨平台文件监听基础设施
  • 可以通过 --checkers、--builders 和 --singleThreaded 控制并行策略
  • 提供 TypeScript 6 / 7 并行运行的过渡方案
  • 继承 TypeScript 6 的默认配置变化,并移除已废弃选项
  • 暂时还需要等待部分生态工具适配新的 API

TypeScript 7.0 更像是一次基础设施升级。它没有改变 TypeScript “为 JavaScript 提供可扩展类型系统”的核心目标,而是让这个目标能够继续服务于更大规模的代码库。

过去,类型检查慢到需要被安排进 CI;现在,它重新变成了本地开发循环的一部分。

这就是 TypeScript 的原生时代。

点击播放