TypeScript 7 升级要并行安装:让 tsc 变快,让 ESLint 留在 TS 6 API

TypeScript 7 最诱人的变化,是把编译器和语言服务迁到了 Go。对每天反复跑 tsc、开编辑器等诊断、让 Agent 一轮轮改代码的人来说,这类性能提升很实在:少一点等待,机器也少一点白白发热。

我这次在这个 Hexo 博客仓库里做了一轮真实升级验证。结论先放前面:这个项目可以让 tsc 使用 TypeScript 7,但不能把根依赖里的 typescript 直接替换成 7。当前更稳的形态是并行安装:tsc 走 TypeScript 7,typescript 这个包名继续给 typescript-eslint、Vue 相关工具和其他需要旧编译器 API 的工具链使用。

为什么值得试

TypeScript 7.0 官方发布文章把它定义成一次 Go native port。官方给出的几个大型仓库全量构建数据很夸张:VS Code 从 125.7 秒到 10.6 秒,Sentry 从 139.8 秒到 15.7 秒,Playwright 从 12.8 秒到 1.47 秒;几个样本里的内存占用也同步下降。

这个变化对 Agent 辅助开发也很关键。Agent 每次改完代码以后,最常做的是跑类型检查、读错误、继续修。tsc 从十几秒降到几秒,单次看着只是少等一会儿,连续迭代时体感会完全不一样。

VS Code 团队的迁移记录也很有参考价值。他们没有一口气切过去,而是先把低风险区域拿来跑 TypeScript 7,再逐步扩大覆盖面。主仓库类型检查从 36 秒降到 5 秒,npm run watch 从大约 80 秒降到 20 秒出头。这个过程说明 TS7 的收益很实在,也说明大项目迁移最好按工具链边界分段推进。

The Register 对这次发布的报道也抓住了同一个点:大型团队以前会把完整 type-check 交给 CI,现在本地重新跑全量检查变得更可接受。至于「MacBook Air 风扇不转、不热了」这类体感反馈,我没有找到足够稳定的公开来源可以当证据写,但方向是合理的:同样的类型检查少跑 CPU、少占内存,设备热量和风扇压力自然会下降。

直接替换会撞到 typescript-eslint

第一步我先按最直接的方式替换:

pnpm add -D typescript@^7.0.2

安装本身能完成,pnpm exec tsc --version 也会变成:

Version 7.0.2

项目里的两个 tsconfig 也能通过:

pnpm run typecheck:build-scripts
pnpm run typecheck:code-lab

问题出在周边工具链。pnpm peers check 会报 @typescript-eslint/parser@typescript-eslint/typescript-estree@typescript-eslint/project-service@typescript-eslint/tsconfig-utils 需要的 peer 范围仍然是 typescript >=4.8.4 <6.1.0

更关键的是运行时也会直接失败。只要 import @typescript-eslint/parser,它就会抛出这段错误:

typescript-eslint does not support TS 7.0.
Please see https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/#running-side-by-side-with-typescript-6.0 to run typescript-eslint using the TS 6 API.
See also https://github.com/typescript-eslint/typescript-eslint/issues/10940 for tracking typescript-eslint's support for TS >=7.1

这不是一个可以靠忽略 peer warning 混过去的问题。TypeScript 7.0 当前还没有稳定的 programmatic API。直接 require('typescript') 只能拿到版本信息:

{
  version: '7.0.2',
  keys: ['version', 'versionMajorMinor'],
  hasScriptTarget: false,
  hasCreateProgram: false
}

typescript-eslint 这类工具需要 createProgramScriptTarget、AST 和类型关系 API。TypeScript 7 的 tsc 能跑,不代表所有把 TypeScript 当库调用的工具都能跑。typescript-eslint 的跟踪 issue也把这个方向标成还需要外部 API 支持。

这次采用并行安装

官方发布文章专门给了 side-by-side 方案:TypeScript 7 提供新的 tsc,同时用 @typescript/typescript6 给仍然需要旧 API 的工具链提供兼容包。

这个仓库最后采用的是:

// sheng-blog/package.json:55-75
{
  "devDependencies": {
    "@typescript/native": "npm:typescript@^7.0.2",
    "typescript": "npm:@typescript/typescript6@^6.0.2"
  }
}

这两个名字的职责要分清楚:

  • pnpm exec tsc 解析到 TypeScript 7.0.2,用来跑项目类型检查。
  • pnpm exec tsc6 可以显式跑旧编译器,当前输出是 6.0.3。
  • require('typescript') 仍然拿到 6.0.3,并且有 createProgramScriptTarget 等旧 API。
  • @typescript-eslint/parser 继续从 typescript 这个包名读取 TS6 API,所以不会被 TS7 的 API 缺口打挂。

并行安装后再跑同一个 parser 验证,结果恢复正常:

{
  astType: 'Program',
  servicesKeys: [
    'emitDecoratorMetadata',
    'experimentalDecorators',
    'isolatedDeclarations',
    'program',
    'esTreeNodeToTSNodeMap',
    'tsNodeToESTreeNodeMap'
  ]
}

这就是这次升级最重要的边界:项目的 CLI type-check 已经可以用 TS7;工具链里需要 TypeScript 作为 JS API 的部分,继续留在 TS6。

本地验证结果

当前验证环境是 Windows、Node v25.8.1、pnpm 11.17.0。升级后跑了这些命令:

pnpm peers check
pnpm run typecheck:build-scripts
pnpm run typecheck:code-lab
pnpm run build:code-lab
pnpm run build:music-player
pnpm run test:kits
pnpm exec hexo clean
pnpm exec hexo generate
git diff --check

结果都是通过。pnpm run test:kits 覆盖了 18 个源码包,包含 @typescript-eslint/parser、Vitest、Stylelint 规则、Vue script setup 规则和几个文章配套工具包。它比单独跑 tsc 更能证明周边工具链没有被 TS7 切换误伤。

另外我专门跑了 pnpm peers check。直接替换成 TS7 时这里会失败;改成并行安装后,结果变成:

No peer dependency issues found

小仓库里的速度也能看出来

这个博客仓库的 TypeScript 体量不大,pnpm exec 自己的启动开销也会占掉不少时间,所以不能拿这里的倍数去类比大仓库。不过同一台机器、同一组命令里,TS7 仍然更快。

目标                   TS7 最快    TS6 最快
build-scripts          1246.4ms    2483.1ms
client/code-lab        1023.5ms    1767.6ms

这组数据包含 pnpm exec 包装开销,实际编译器差距会被压小。即便这样,两个项目的最快样本也都有明显下降。对更大的业务仓库,收益通常会更接近官方和 VS Code 团队给出的数量级。

升级口径

这次之后,我会把 TS7 升级分成三种情况判断:

  • 只跑 tsc --noEmit 的项目:优先试 TypeScript 7。先跑 TS6 和 TS7 对照,再看类型错误是否一致。
  • typescript-eslint、Vue、Svelte、Astro、Angular 模板类型检查的项目:先用并行安装。tsc 用 TS7,typescript 包名保留 TS6 API。
  • 依赖 TypeScript programmatic API 的构建插件或 loader:不要只看 tsc 是否通过。必须直接 import 对应插件、跑真实构建或测试,因为 TS7.0 的 API 缺口会在这里暴露。

等 TypeScript 7.1 的 API 和生态支持更完整以后,可以重新评估是否把 typescript 这个包名也切回 7。现在这个阶段,更稳的做法是让快的部分先快起来,让还没跟上的工具继续用它能理解的 TS6 API。