2026 年 3 月 23 日,TypeScript 6.0 正式发布了。这个版本有点特殊——按微软的说法,它是基于当前 JavaScript 代码库的最后一个大版本。下一个版本 7.0 会换成用 Go 写的编译器,性能会有一个质的飞跃。
所以 TypeScript 6.0 更像是 5.9 和 7.0 之间的一个过渡桥。这篇文章会从几个角度拆解 6.0:它到底带来了什么新东西、有哪些坑要踩、升级的时候要注意什么,以及 7.0 那边已经在酝酿什么了。

先总结
– TypeScript 6.0 = 最后一个 JS 代码库的大版本
– 新特性亮点:Temporal API 类型、Map.upsert 方法、ES2025 target、this-less 函数的类型推断优化
– 多项目配置默认值变了(`types` 默认变 `[]`、`rootDir` 默认变 `.`)
– 废弃警告:`target: es5`、`–baseUrl`、老式 namespace 的 `module` 语法
– 7.0 已经可以体验 Native Preview
为什么说这是一个特殊的版本
TypeScript 团队去年就宣布了要把编译器用 Go 重写。原因很简单:项目大了以后,TypeScript 的编译和类型检查速度确实是痛点。你见过大公司 monorepo 跑一次类型检查等好几分钟吗?Go 版本可以利用原生代码速度和共享内存多线程,理论上会有数量级的提升。
但这么大的工程不可能一步到位。6.0 就是中间那个”承上启下”的版本:它在 JS 代码库里实现了尽量接近 7.0 的行为,让开发者能在升 7.0 之前先把代码调好。
新特性详解
1. 对不涉及 this 的函数减少上下文敏感性
这个改进看起来很技术细节,但对日常写代码影响不小。
看个例子:
```typescript
declare function callIt(obj: {
produce: (x: number) => T,
consume: (y: T) => void,
}): void;
// 箭头函数写法,没问题
callIt({
consume: y => y.toFixed(),
produce: (x: number) => x * 2,
});
// 换成方法语法,在 5.x 里就报错了
callIt({
consume(y) { return y.toFixed(); }, // ← error: 'y' is of type 'unknown'
produce(x: number) { return x * 2; },
});
```
区别在于方法语法有隐式的 `this` 参数,箭头函数没有。TypeScript 在泛型推断时会把这种函数标记为”上下文敏感”然后跳过,推断就失败了。
6.0 的解法很直接:如果函数里根本没用到 `this`,那就不算上下文敏感,直接参与类型推断。上面的代码在 6.0 里就都能跑了。
社区贡献者 Mateusz Burzyński 提交的这个改动,虽然小但很实用。
2. 支持以 `#/` 开头的子路径导入
Node.js 的子路径导入(subpath imports)是个好东西,让你在 `package.json` 里定义内部别名,不用写一长串的 `../../../`。
但之前有个很烦的限制:子路径必须以 `#xxx/` 开头,不能直接用 `#/`。
```json
// 以前必须这样
{
"imports": {
"#root/*": "./dist/*"
}
}
// 现在可以这样了
{
"imports": {
"#/*": "./dist/*"
}
}
```
Node.js 新版 20.x 已经支持,TypeScript 6.0 也跟进了。`–moduleResolution nodenext` 或 `bundler` 模式下都能用。
3. `–moduleResolution bundler` 现在可以和 `–module commonjs` 搭配
之前 `–moduleResolution bundler` 只允许和 `–module esnext` 或 `–module preserve` 搭配。随着老旧的 `–moduleResolution node`(node10)被废弃,很多正在迁移的项目迫切需要更灵活的搭配。
6.0 放开了这个限制。微软还是建议你最终往两个方向之一迁移:
– `–module preserve` + `–moduleResolution bundler`(适合打包的 web 应用或 Bun 应用)
– `–module nodenext`(适合 Node.js 应用)
4. `–stableTypeOrdering` 迁移辅助标志
这个标志纯粹是为了升 7.0 准备的。
现在的 TypeScript 给类型分配 ID 的方式挺原始的——按遇到顺序来。这就导致了一个奇怪的现象:你在文件里加了个不相关的 `const`,输出的 `.d.ts` 文件里联合类型顺序就可能变。
```typescript
// 输入
export function foo(condition: boolean) {
return condition ? 100 : 500;
}
// 输出:100 | 500
// 如果在上面加 const x = 500,输出就变成 500 | 100 了
```
正常情况下问题不大,问题在于 TypeScript 7 的并行类型检查会打乱类型创建顺序,导致非确定性输出。7.0 的解决方案是用基于内容本身的确定性排序算法来替代现在的顺序 ID。
6.0 的 `–stableTypeOrdering` 就是让你在迁移过程中模拟 7.0 的排序行为,方便对比输出差异。
不过注意:这标志会拖慢类型检查速度,极端可能慢 25%,只建议在迁移诊断时用。
5. ES2025 target 与 lib
ES2025 本身没有新增 JavaScript 语法特性,但多了几个内置 API:
– `RegExp.escape`:安全地转义字符串中的正则特殊字符
– `Promise.try`:从 esnext 移到 es2025
– Iterator 方法、Set 方法:从 esnext 移到 es2025
```typescript
function matchWholeWord(word: string, text: string) {
const escapedWord = RegExp.escape(word);
const regex = new RegExp(`\\b${escapedWord}\\b`, "g");
return text.match(regex);
}
```
6. Temporal API 类型支持
Temporal 提案终于走到 Stage 4,TypeScript 6.0 内置了它的类型定义。终于可以不再被 `Date` 的各种诡异行为折磨了。
```typescript
let yesterday = Temporal.Now.instant().subtract({ hours: 24 });
let tomorrow = Temporal.Now.instant().add({ hours: 24 });
```
通过 `–target esnext` 或 `”lib”: [“esnext”]` 就能用。
7. Map.upsert 方法(getOrInsert / getOrInsertComputed)
以前要给 Map 设个默认值要写好几行:
```typescript
// 以前
let strictValue: unknown;
if (compilerOptions.has("strict")) {
strictValue = compilerOptions.get("strict");
} else {
strictValue = true;
compilerOptions.set("strict", strictValue);
}
// 现在
let strictValue = compilerOptions.getOrInsert("strict", true);
```
默认值计算成本高的话,还有 `getOrInsertComputed`,接受一个回调,只有 key 不存在时才执行。
8. DOM 类型更新和 dom.iterable 合并
从 6.0 开始,`lib.dom.d.ts` 已经包含了原来在 `lib.dom.iterable.d.ts` 和 `lib.dom.asynciterable.d.ts` 里的内容。之前需要手动写 `”lib”: [“dom”, “dom.iterable”]` 才能调 `querySelectorAll` 的迭代功能,现在只用 `”lib”: [“dom”]` 就行。
DOM 类型本身也做了更新,Temporal API 的相关类型做了调整。
默认值变更
TypeScript 6.0 调整了几个关键的默认值,直接升可能会踩坑。
`types` 默认为 `[]`
改动面最广的一个。以前 `types` 默认会加载所有 `@types/*` 包,你的代码可能无意中依赖了某些类型定义。现在默认是空数组,只有在 `tsconfig.json` 里显式列出 `@types` 包才会加载。
新项目不受影响,旧项目升上来可能会发现一堆找不到的类型错误。
`rootDir` 默认为 `.`
之前如果没设 `rootDir`,TypeScript 会根据入口文件自动推断。自动推断的逻辑有时候挺蛋疼的——特别是 `src/` 和 `tests/` 混在一起时,输出目录结构容易乱。
现在默认设成 `.`(`tsconfig.json` 所在目录),行为更可预期了。
默认启用严格模式
严格模式在 6.0 里成了默认值,新项目开箱就有 `strict: true`。
废弃项(7.0 会移除)
– `target: es5`:还在,但标记为废弃了,7.0 会彻底移除。还在用 ES5 的项目差不多该升级了
– `–baseUrl`:被废弃,建议改用路径映射或 subpath imports
– `module` 关键字作为 namespace 的写法:`module Foo { … }` 以后都要改成 `namespace Foo { … }`
– `asserts` 关键字在 import 上的用法:`import … assert { … }` 要改用 `import … with { … }`
– `–no-default-lib` 指令:被废弃
– 存在 tsconfig.json 时在命令行指定文件变成错误:以前可以 `tsc src/index.ts` 即使有 `tsconfig.json`,现在会报错
怎么升到 6.0
1. 先跑一次 `npx typescript@latest` 看看有多少错误
2. 处理 `types` 默认为 `[]`:在 `tsconfig.json` 里显式列出你用的 `@types` 包
3. 检查 `rootDir`:如果已经在用,确认行为没变
4. 处理废弃警告:把 `es5` target 切到 `es2015` 或更高,把 `module` 写法改成 `namespace`
5. 试试 `–stableTypeOrdering`:如果打算后续升 7.0,可以用这个标志提前检查
TypeScript 7.0 前瞻
6.0 发布的同时,7.0 的 Native Preview 已经可以在 VS Code 和 npm 上体验了。
7.0 的核心变动是编译器用 Go 重写(项目内部叫 `tsgo`),带来的好处:
– 原生代码速度(不再受 JIT 预热限制)
– 共享内存多线程并行类型检查
– 确定性类型排序(不再出现上面说的声明文件顺序抖动)
微软说 7.0 “actually extremely close to completion”,很可能在 6.0 之后不久就会发布正式版。
如果你已经有能力升到 6.0,官方甚至建议直接去试试 7.0 的 Native Preview。
升级建议
分情况考虑:
– 新项目:直接上 6.0,甚至可以考虑体验 7.0 Preview
– 中小型项目:升 6.0 风险不大,默认值变更大多有明确的修复指引
– 大型 monorepo:先小范围试,把 `types` 默认值变更处理好再逐步推广
– 还在用 ES5 target:得先解决 target 升级的问题,这是最棘手的依赖
总的来说,TypeScript 6.0 不是一个”不升就落伍”的大版本,但考虑到 7.0 马上就来,现在提前适配是对的。
—
参考来源:
[TypeScript 6.0 Release Notes]
📖 推荐阅读
看看这些文章,你可能会感兴趣:
React Server Components 指南:原理、实战与框架对比
浅析:Next.js 15 为什么成为 Agentic AI 应用标准?