12k
All articles

现在应该升级到 TypeScript 7 吗?

现在该升级到 TypeScript 7 吗?比较编译器速度、破坏性变更和工具兼容性,选择适合项目的安全迁移方案。

OpenReplay Team
OpenReplay Team
现在应该升级到 TypeScript 7 吗?

如果你的项目是纯 TypeScript 项目,并且已经能在 6.0 上干净地构建,那就现在升级到 TypeScript 7。如果你依赖 typescript-eslint、Vue、Svelte、Astro、MDX 或 Angular 模板检查,请将 7.0 的 tsc 与 6.0 并行运行,等到 7.1 再完全切换。

性能数字确实诱人。但你转念一想:lint 流水线、.vue 文件,还有一个自定义的代码生成脚本,全都 import 了 typescript。这样一来,大版本升级就显得有些冒险了。

TypeScript 7.0 于 2026 年 7 月 8 日正式发布。本文将介绍其性能提升的实际表现、哪些配置变更会导致构建失败、哪些工具暂时还无法使用 7.0,以及如何在同一个仓库中同时运行两个版本的编译器。文末会针对不同类型的项目给出建议。

核心要点

  • TypeScript 7.0 是将编译器移植到 Go 语言的版本。微软报告称,在五个大型开源代码库上,完整构建速度比 6.0 快 7.7 到 11.9 倍。
  • TypeScript 6.0 中所有已弃用的选项在 TypeScript 7.0 中都会直接报错,包括 target: es5、downlevelIteration、baseUrl、node10 和 classic 模块解析,以及 amd、umd 和 systemjs 模块格式。
  • TypeScript 7.0 不提供编程式 API,因此将编译器作为库导入的工具(例如 typescript-eslint)必须通过 @typescript/typescript6 包继续运行在 6.0 上。
  • Vue、MDX、Astro 和 Svelte 项目目前应继续使用 TypeScript 6.0;Angular 团队可以在 CI 中使用 7.0 的 tsc,同时在编辑器中保留 6.0。

TypeScript 7 到底快了多少?

TypeScript 7.0 是 TypeScript 编译器的 Go 语言移植版本。微软表示,与 TypeScript 6.0 相比,完整构建通常会快 8 到 12 倍。团队并没有重新设计编译器,Go 版本沿用了原有代码的组织方式和运行机制,因此两个编译器会给出相同的结果。性能提升来自原生代码执行,以及基于共享内存的多线程类型检查。

以下是来自微软 TypeScript 7.0 发布公告的完整构建数据:

代码库TypeScript 6TypeScript 7提速
vscode125.7s10.6s11.9x
sentry139.8s15.7s8.9x
bluesky24.3s2.8s8.7x
playwright12.8s1.47s8.7x
tldraw11.2s1.46s7.7x

微软在大型开源代码库上运行这些构建时,使用的是默认的四个类型检查 worker(--checkers 4)。公告中没有说明所用的硬件配置。其中最低的结果是 tldraw 的 7.7 倍,略低于微软所称的”8 到 12 倍”区间。

TypeScript 7 实际能节省多少时间,取决于代码库的规模。根据微软的数据推算,vscode 每次完整构建可节省约 115 秒,而 tldraw 节省不到 10 秒。一个类型检查本来只需两秒的小型应用,提速比例虽然相近,但实际节省的时间微乎其微。

另外还有三项较小的改动,各用一句话概括:

  • --checkers 和 --builders 分别控制并行类型检查和项目引用(project references)构建。7.0 的发布说明将这两个标志都标记为实验性功能。
  • --watch 现在基于 Parcel 文件监听器的 Go 移植版本运行。
  • JS 和 JSDoc 检查经过重构,行为更接近 .ts 文件的分析方式。详细信息见 typescript-go 的 CHANGES.md。

从 TypeScript 5.x 或 6.0 升级会遇到哪些破坏性变更

在 TypeScript 6.0 上没有任何错误的代码(开启 stableTypeOrdering 并移除 ignoreDeprecations 后),在 TypeScript 7.0 上应该得到相同的输出。所有破坏性变更都源自 6.0:7.0 继承了 6.0 的新默认值,而 6.0 中标记为弃用的内容现在会直接中断构建。直接从 5.x 升级的团队需要同时应对这两批变更。

新的默认值

从 6.0 延续下来的四个 TypeScript 7.0 默认值,导致了大部分破坏性问题:

  • strict 默认为 true。类型宽松的代码会出现新的报错。借助 TypeScript 工具类型编写类型完善的辅助代码,可以让过渡更顺利。
  • module 默认为 esnext。
  • rootDir 默认为 ./。如果你的 tsconfig.json 位于 src 的上层目录,请显式设置 rootDir。
  • types 默认为 []。需要按名称列出全局类型包,例如 node 或 jest,或者设置为 ["*"] 以恢复旧行为。

还有四个默认值也发生了变化:target 现在跟随最新定稿的 ECMAScript 版本(比 esnext 落后一个版本);noUncheckedSideEffectImports 为 true;libReplacement 为 false;stableTypeOrdering 为 true 且无法关闭。

已变为硬错误的弃用项

TypeScript 7.0 发布说明列出了十二项已弃用的选项和行为,它们现在都会直接报错:

  • target: es5
  • downlevelIteration
  • moduleResolution: node / node10(改用 nodenext 或 bundler)
  • moduleResolution: classic(改用 bundler 或 nodenext)
  • module: amd、umd、systemjs、none(改用 esnext 或 preserve)
  • baseUrl(将 paths 改为相对于项目根目录书写)
  • 将 esModuleInterop 或 allowSyntheticDefaultImports 设置为 false
  • 将 alwaysStrict 设置为 false
  • 在命名空间声明中使用 module 关键字
  • 在 import 上使用 asserts(改用 with)
  • 在 skipDefaultLibCheck 下使用 /// <reference no-default-lib />
  • 当目录中存在 tsconfig.json 时在命令行中传入文件路径,除非添加 --ignoreConfig

outFile 虽然不在上述列表中,但同样已被移除。6.0 的发布说明指出,6.0 已经移除了它,并且 6.0 中弃用的所有选项都会在 7.0 中彻底移除。如果你仍在使用 outFile,请将这部分工作交给打包工具(bundler)。

此外还有一项类型层面的变更:从模板字面量类型进行推断时,不再会把 emoji 之类的字符拆成两半。只有当你编写过依赖旧的 UTF-16 拆分行为的类型级字符串工具时,才会注意到这一点。

下面是一个典型的旧版配置,以及可以在 7.0 上运行的新版本:

// Before: hard errors on 7.0
{
  "compilerOptions": {
    "target": "es5",               // error: es5 unsupported
    "downlevelIteration": true,    // error: removed
    "moduleResolution": "node",    // error: node/node10 unsupported
    "baseUrl": "./src",            // error: baseUrl unsupported
    "paths": { "@/*": ["*"] }
  },
  "include": ["./src"]
}
// After: valid on 7.0
{
  "compilerOptions": {
    "moduleResolution": "bundler",
    "rootDir": "./src",
    "types": ["node", "jest"],
    "paths": { "@/*": ["./src/*"] }
  },
  "include": ["./src"]
}

新版本去掉了 target 以使用默认值,将 paths 改为相对于项目根目录,并显式设置了 rootDir 和 types。

微软建议先迁移到 6.0。升级到 6.0,修复所有弃用警告(TypeScript 6.0 发布公告对每一项都有说明),移除 ignoreDeprecations,然后再安装 7.0。

哪些工具暂时无法使用 TypeScript 7?

将 TypeScript 编译器作为库导入的工具,以及支撑 Vue、MDX、Astro、Svelte 和 Angular 模板检查的工具,目前都无法使用 TypeScript 7.0,因为 TypeScript 7.0 不提供编程式 API。根据微软的 7.0 发布公告,将编译器作为库导入的工具(例如 typescript-eslint)必须通过 @typescript/typescript6 兼容包继续运行在 TypeScript 6.0 上。如果你的 typescript-eslint 类型感知 lint 配置依赖于 typescript 这个 peer dependency,就需要采用下一节介绍的别名配置。

嵌入式语言同样受到影响。微软的 7.0 发布公告表示,Vue、MDX、Astro 和 Svelte 项目目前应继续使用 TypeScript 6.0。Volar 等工具通过直接调用编译器,为这些文件格式提供 TypeScript 支持,而 7.0 没有可供它们调用的 API。Angular 模板类型检查也存在同样的限制。对于 Angular,公告建议分而治之:在命令行和 CI 中使用 7.0 的 tsc,快速发现整个项目中的错误;编辑器则继续交给 6.0 负责,以保证模板检查正常工作。

在 VS Code 中,微软专门的 TypeScript 7 扩展提供了两个命令面板命令:“Disable TypeScript 7 Language Server” 和 “Enable TypeScript 7 Language Server”,你可以随时让编辑器在 6.0 和 7.0 之间切换。如果切换后编辑器出现异常,常规的 VS Code 中的 TypeScript 调试流程依然适用。

微软计划在 TypeScript 7.1 中重新加入 API,但不会与旧版 API 保持一致。届时才是这些集成工具迁移过去的现实时间点。

如何同时运行 TypeScript 7 和 6.0

要在同一个仓库中运行两个版本,可以使用 npm 别名:将 typescript 这个包名指向 6.0 兼容包,并以另一个名称安装 7.0。这样,导入 typescript 的工具加载的就是 6.0。兼容包提供 6.0 的 API,以及一个名为 tsc6 的 6.0 命令。

在普通的 npm 项目中,npx tsc 运行的就是 7.0。但这里有个坑:兼容包依赖一份完整的 TypeScript 6.0,而后者也声明了自己的 tsc,于是两个包会争夺这个命令名。有用户报告 Yarn 和 Bun 可能会把 tsc 链接到 6.0。下面的 typecheck 脚本直接调用 7.0 的文件,因此不受哪个包抢到 tsc 命令名的影响。这是微软描述的配置方式,这里补充了脚本示例:

{
  "devDependencies": {
    "@typescript/native": "npm:typescript@^7.0.2",
    "typescript": "npm:@typescript/typescript6@^6.0.2"
  },
  "scripts": {
    "typecheck": "node node_modules/@typescript/native/bin/tsc --noEmit",
    "typecheck:6": "tsc6 --noEmit",
    "lint": "eslint ."
  }
}

typecheck 运行 7.0。typecheck:6 运行 6.0,可用于在迁移期间确认两个编译器的结果一致。lint 通过别名将 typescript 解析为 6.0。如果想在终端中配置 6.0 别名,可以运行 npm install -D typescript@npm:@typescript/typescript6。但如果只执行这一步,你只会得到 tsc6,因此还需要再添加 7.0 的别名。

运行 npx tsc --version 可以查看直接调用 tsc 时使用的是哪个编译器。微软只针对 npm 给出了这套配置的文档,如果你使用 pnpm、Yarn 或 Bun,请自行验证结果。

该不该升级?分场景给出建议

是否升级到 TypeScript 7 取决于两点:你的 6.0 构建是否干净,以及工具链中是否有工具导入了编译器。

场景建议原因
新项目采用 7.0没有历史配置包袱,从第一天起就享受新默认值
小型纯 TS 代码库在 6.0 构建干净后升级干净的 6.0 构建可以平移到 7.0 并得到相同结果
大型 monorepo、自定义工具链,或 Vue/Svelte/Astro/MDX/AngularCI 中使用 7.0 的 tsc,工具和编辑器使用 6.0工具和嵌入式语言需要 7.0 尚未提供的 API

**新项目:**直接从 7.0 起步。如果你正在从 Flow 迁移到 TypeScript,一开始就以 7.0 的默认值为目标,避免二次迁移。

**小型纯 TS 代码库:**先升级到 6.0,修复所有弃用项,然后再切换。节省的时间不多,但你会处在持续维护的版本线上。

**大型 monorepo:**配置好别名,现在就把 CI 中的类型检查迁移到 7.0 的 tsc,而 lint、代码生成和编辑器则保留在 6.0,直到 7.1 发布 API。

结论

TypeScript 7.0 对代码的类型检查与 6.0 几乎完全一致,只是更快。几乎所有破坏性问题都来自 6.0 的弃用项,或者来自需要编译器 API 的工具。第一步是在不使用 ignoreDeprecations 的情况下,让 6.0 构建保持干净。之后,你可以选择完全切换,或者添加 npm 别名,让 CI 运行 7.0 的 tsc,而工具链继续使用 6.0,直到 7.1 发布。

常见问题

tsgo 或 @typescript/native-preview 和 TypeScript 7 是一回事吗?

现在已经不是了。在 7.0 正式发布之前,Go 编译器以 @typescript/native-preview 包的形式提供预览,其命令为 tsgo。该包的最后一个版本是 7.0.0-dev.20260707.2,发布于正式版的前一天。在 TypeScript 7.0 中,原生编译器已并入常规的 typescript 包,并以 tsc 命令运行。nightly 构建现在通过 typescript@next 获取,因此请将 CI 脚本中的 tsgo 改为 tsc。

TypeScript 7 会让 Vite、esbuild 或 SWC 构建更快吗?

不会。Vite、esbuild 和 SWC 将 TypeScript 转换为 JavaScript 时只是擦除类型,不做类型检查,因此它们从不调用 tsc,转译时间也不会改变。TypeScript 7 提速的是独立的类型检查步骤(通常是 CI 或 pre-commit 钩子中的 tsc --noEmit)以及编辑器的语言服务器。如果类型检查不是流水线中最慢的环节,升级并不会让构建时间明显缩短。

ts-node 能配合 TypeScript 7 使用吗?

不能直接使用。ts-node 通过 TypeScript 编译器 API 编译文件,而 7.0 并不提供该 API。采用 npm 别名配置后,ts-node 对 typescript 的导入会解析到 6.0 兼容包,因此它会继续在 6.0 上运行,而 tsc 则运行 7.0。对于只使用可擦除语法的代码,较新版本 Node.js 的类型剥离(type stripping)功能可以在完全不借助编译器的情况下运行 .ts 文件,但它不做任何类型检查。

TypeScript 7 还能为旧版浏览器编译到 ES5 吗?

不能。TypeScript 6.0 已将最低支持的 target 提升到 ES2015,并弃用了 target es5。在 7.0 中,target es5 会直接报错。如果仍然需要 ES5 输出,可以让 tsc 输出 ES2015 或更高版本,再用 Babel 或其他编译器对结果进行后处理。或者,也可以直接用这类外部工具编译 TypeScript 源码。

Open-source session replay

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.