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默认值变为truemodule默认值变为esnexttarget默认使用紧邻esnext之前的稳定 ECMAScript 版本noUncheckedSideEffectImports默认值变为truelibReplacement默认值变为falsestableTypeOrdering默认值变为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: es5downlevelIterationmoduleResolution: node或node10moduleResolution: classicmodule: amd、umd、systemjs、nonebaseUrl- 将
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 ServerDisable TypeScript 7 Language Server
但需要注意,Vue、MDX、Astro、Svelte 等嵌入式语言工作流暂时可能无法直接使用 TypeScript 7。原因是这类工具会把 TypeScript 嵌入自己的编译器或语言服务中,而 TypeScript 7 目前还没有稳定的程序化 API。
因此,比较现实的迁移策略是:
- 在 CI 中先使用 TypeScript 7 执行完整类型检查。
- 对不依赖语言服务插件的纯 TypeScript 项目启用 TypeScript 7。
- Vue、MDX 等项目暂时保留 TypeScript 6 的编辑器支持。
- 等相关生态完成 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 的原生时代。