编码面试:如何安全迁移到 TypeScript 7 原生编译器?
题干与适用场景
你的团队在一个 TypeScript 6 monorepo 中维护 Web 应用和共享包。CI 类型检查耗时过长,仓库同时使用 typescript-eslint、webpack loader,以及 Vue、Angular 模板工具。现在要评估 TypeScript 7 原生编译器。
请设计迁移方案,说明如何保留 TypeScript 6 兼容层、安排 CLI 与编辑器升级、控制并行检查的内存风险,并定义灰度、指标与回滚条件。
面试官考察点
- 能否区分
tsc命令行、编辑器语言服务和程序化 TypeScript API 的依赖。 - 能否用锁定版本、双编译器和可比较产物降低迁移风险。
- 能否把并行度、内存、诊断差异和生态兼容性转化为可执行的发布门槛。
- 能否说明 TypeScript 7 尚未提供稳定程序化 API 时的边界。
回答前需要澄清的问题
- 当前 CI 使用的是
tsc --build、独立项目还是自定义编译器 API? - 哪些工具直接导入
typescript,哪些只读取声明文件或命令行输出? - 是否已经启用 TypeScript 6 的
stableTypeOrdering,并保存了声明、诊断和构建时间基线? - 编辑器版本、Node 内存上限和 CI runner 的 CPU/内存规格是否固定?
30 秒回答
我会先盘点所有 TypeScript API 消费者,再把 TypeScript 7 CLI 与 TypeScript 6 兼容包并行安装,锁定版本和 lockfile。先在 CI 对比声明文件、诊断、生成 JavaScript、source map、测试结果和资源用量;TypeScript 6 侧先启用 stableTypeOrdering。TypeScript 7 的 --checkers、--builders 只按基准逐步调大,并保留 --singleThreaded 作为诊断开关。没有稳定程序化 API 的 Vue、MDX、Astro、Svelte、Angular 工具继续使用 TypeScript 6。通过 canary、编辑器分批和明确回滚版本推进,达标后才扩大范围。
分步骤深入解答
盘点编译器与 API 依赖
记录 Node、包管理器、TypeScript、tsconfig、project references、loader、插件和编辑器版本。把消费者分为 CLI、声明/生成产物、语言服务和程序化 API;程序化 API 需要单独的兼容性验证。
采用 TypeScript 7 与 TypeScript 6 双轨安装
TypeScript 7 当前提供原生编译器,但还没有稳定 API。可以让 tsc 使用 7,同时用 npm alias 保留 tsc6:
{
"devDependencies": {
"@typescript/native": "npm:typescript@^7.0.2",
"typescript": "npm:@typescript/typescript6@^6.0.2"
}
}实际仓库应固定经过验证的版本并提交 lockfile;脚本要显式调用对应二进制,避免包管理器扁平化后误用编译器。
建立可比较的产物基线
先在 TypeScript 6 启用 stableTypeOrdering,保存 .d.ts、诊断、生成 JavaScript、source map、增量构建缓存和测试结果。对比时区分排序变化、真实类型错误和工具自身格式差异;只把可解释且不影响 API 的变化纳入允许清单。
调节 checker 与 builder 并行度
TypeScript 7 的 checker 默认使用 4 个 worker;builder 也可并行。先以固定 CPU、内存和项目顺序测量,再逐级提高并行度。记录墙钟时间、峰值 RSS、GC 和失败重试;超过 runner 内存预算就回退。遇到非确定性时用 --singleThreaded 复现并保留固定 worker 数作为 CI 配置。
隔离生态工具与编辑器升级
没有稳定程序化 API 时,不要强迫模板工具一起升级。Vue、MDX、Astro、Svelte、Angular 等工具可能仍依赖 TypeScript 6 API,可让它们继续消费 tsc6 或维持独立的 TS6 语言服务。编辑器先在少量开发者频道启用对应扩展,观察补全、跳转、诊断和崩溃率。
灰度、指标与回滚
先选择低风险包和一条 CI canary,比较构建时间、诊断差异、声明兼容性、内存峰值、编辑器错误和测试通过率。失败时恢复旧 lockfile、旧脚本和 TS6 editor channel;不要只删除 TS7 包而留下不匹配的 loader。等所有门槛连续通过后再扩大到其他 workspace。
高质量示范回答
TypeScript 7 的价值在于原生编译器和更快的 CLI,但迁移的边界由 API 消费者决定。我会建立“TS7 做 CLI、TS6 做兼容层”的双轨方案:锁定两个版本,显式提供 tsc 与 tsc6,并将 loader、模板工具和编辑器按是否依赖程序化 API 分流。基线阶段先启用 stableTypeOrdering,逐项比较声明、诊断、生成物、source map、测试和资源用量。并行参数按固定 runner 基准调优,--singleThreaded 用于复现问题。通过 canary、编辑器小流量和连续通过门槛后逐步扩大;任何诊断回归、声明破坏、内存超限或编辑器故障都触发回滚。由于 TypeScript 7 还没有稳定程序化 API,保留 TS6 直到生态工具完成适配,才是可逆的发布路径。
常见错误
- 只替换
typescript版本,却没有检查 loader、插件和模板工具是否导入 TypeScript API。 - 把所有速度提升归因于原生编译器,没有记录本仓库基线和内存成本。
- 未启用
stableTypeOrdering就把声明排序变化当成类型回归。 - 让 CI 追求最大并行度,忽略 runner 内存和失败重试。
- 因为 CLI 能运行,就假设编辑器和程序化 API 已经兼容。
- 只准备“卸载 TS7”的口头回滚,没有保留 lockfile、脚本和编辑器版本。
追问及应对
如果某个 loader 依赖 TypeScript 6 API,能否只升级 CI?
可以先只升级类型检查 canary,loader 继续调用 tsc6 或 TypeScript 6 API;必须验证生成物和声明文件一致,再决定是否升级 loader。
--checkers 越大越好吗?
不一定。并行度受 CPU、内存、项目图和 GC 影响,应以固定 runner 的墙钟时间和峰值 RSS 共同决定,并保留较小值作为回退配置。
什么时候可以移除 TypeScript 6?
当所有程序化 API 消费者、模板工具、编辑器和构建插件完成兼容性验证,且 canary 指标连续达标;TypeScript 7 稳定 API 可用后再评估移除兼容层。
如何证明类型结果没有变化?
比较诊断、声明文件、生成 JavaScript、source map 与测试结果,并对排序变化和格式差异做分类;不能只比较退出码。