TypeScript 6.0 正式发布:这些变更让你的项目直接报错

10 阅读7分钟

升级 TS 6 之前,这篇文章值得先看一遍。

前言:为什么这次升级特别容易翻车

TypeScript 6.0 在 2026 年 3 月正式发布。如果你去看官方发布说明,会发现一个很有意思的定位——这是最后一个基于 JavaScript 代码库的 TypeScript 版本

TypeScript 7 将基于 Go 重写的原生编译器(Project Corsa),届时构建速度会有数量级提升。而 TS 6 的核心任务,就是清理旧时代配置包袱、对齐 TS 7 行为,让这个过渡尽可能平滑。

这意味着什么?意味着 TS 6 的变更不炫技,但很实在。它没有给你带来多少"哇塞"的新语法,而是把一批用了多年的默认值改了。

而这,恰恰是最容易让人翻车的地方。

你的项目里大概有这些情况吗?

  • tsconfig.json 里没有显式写 strict
  • 用的是 CommonJS 风格的项目
  • 依赖 @types/node 等全局类型
  • baseUrl + paths 做路径别名
  • 项目结构里 tsconfig.json 和源码目录不在同一层

如果有,那升级 TS 6 后大概率会遇到编译报错。这篇文章帮你把坑提前排掉。

一、strict 默认变成 true

变更内容

表格

版本strict 默认值
TS 5.xfalse
TS 6.0true

strict 不是单个开关,而是一组严格类型检查的集合:

{
  "strict": true
}

等价于同时开启:

  • strictNullChecks
  • noImplicitAny
  • strictFunctionTypes
  • strictPropertyInitialization
  • noImplicitThis
  • alwaysStrict

为什么会报错

很多老项目习惯不写 strict,依赖一些"宽松"的隐式类型推断。升级后这些代码会直接报错:

// ❌ 报错:Parameter 'x' implicitly has an 'any' type
function processData(x) {
  return x.value;
}

// ❌ 报错:Argument of type 'string | undefined' is not assignable
function greet(name: string) {
  console.log(name.toUpperCase());
}
greet(Math.random() > 0.5 ? "Alice" : undefined);

// ❌ 报错:Property 'name' has no initializer
class User {
  name: string;
}

怎么修

方案一:先稳住,再逐步收紧

如果项目较大、暂时没时间处理所有类型问题,先显式写回旧行为:

{
  "compilerOptions": {
    "strict": false
  }
}

方案二:逐项开启(推荐长期方案)

不要一次性开全部,分批处理更容易定位问题:

{
  "compilerOptions": {
    "noImplicitAny": true
  }
}

跑通后继续:

{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true
  }
}

最后:

{
  "compilerOptions": {
    "strict": true
  }
}

诊断命令

# 升级后快速查看报错数量
npx tsc --noEmit 2>&1 | grep "error TS" | wc -l

# 按错误类型统计,优先处理高频问题
npx tsc --noEmit 2>&1 | grep "error TS" | cut -d'(' -f1 | sort | uniq -c | sort -rn | head -20

二、module 默认变成 esnext

变更内容

表格

版本module 默认值
TS 5.xcommonjs
TS 6.0esnext

为什么会报错

如果你还在用 CommonJS 风格的项目(require/module.exports),升级后:

// ❌ 如果是 .ts 文件,require 语法直接报错
const express = require('express');
module.exports = router;

// ❌ 即使配置了,混合语法在 esnext 模块下更容易出问题
const fs = require('fs');  // ❌
import fs from 'fs';      // ✅

怎么修

方案一:迁移到 ESM

{
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "bundler"
  }
}

同时在 package.json 声明:

{
  "type": "module"
}

方案二:保持 CommonJS(保守方案)

{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "nodenext"
  }
}

方案三:渐进式迁移(推荐)

先用 esnext 模块但保持 moduleResolution: "bundler",这是现代前端项目的主流组合:

{
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "bundler",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  }
}

三、types 默认变成空数组

变更内容

表格

版本types 默认值
TS 5.x自动扫描 node_modules/@types 全部包
TS 6.0[](空数组,不再自动引入)

为什么会报错

这大概是升级 TS 6 后最容易遇到的报错来源

升级后你会发现:

// ❌ 报错:Cannot find name 'process'
console.log(process.env.NODE_ENV);

// ❌ 报错:Cannot find name 'setTimeout' / 'setInterval'
setTimeout(() => {}, 1000);

// ❌ 报错:Cannot find name 'describe' / 'it' / 'expect'
describe('test', () => {
  it('works', () => {
    expect(true).toBe(true);
  });
});

因为 @types/node@types/jest 这些包提供的全局类型,TS 6 不再默认导入了。

怎么修

显式声明你需要的类型包

{
  "compilerOptions": {
    "types": ["node", "jest"]
  }
}

常见项目类型配置参考:

// Node.js 后端项目
{
  "compilerOptions": {
    "types": ["node"]
  }
}

// React + Jest 测试
{
  "compilerOptions": {
    "types": ["node", "jest", "@testing-library/jest-dom"]
  }
}

// Vite 项目
{
  "compilerOptions": {
    "types": ["vite/client"]
  }
}

临时过渡方案(不推荐长期使用):

如果暂时不想一个个加,可以先这样恢复旧行为:

{
  "compilerOptions": {
    "types": ["*"]
  }
}

但这违背了 TS 6 改进的初衷——自动引入所有 @types 会拖慢编译速度,官方说有的项目能快 20-50%。

四、rootDir 默认变成 '.'

变更内容

表格

版本rootDir 默认值
TS 5.x自动推断源码公共目录
TS 6.0'.'(tsconfig.json 所在目录)

为什么会报错

典型的输出目录问题:

project/
├── tsconfig.json
└── src/
    └── index.ts

之前你可能期望输出:

dist/index.js

升级后如果没配置 rootDir,输出可能变成:

dist/src/index.js

怎么修

推荐配置

{
  "compilerOptions": {
    "rootDir": "./src",
    "outDir": "./dist",
    "include": ["src"]
  }
}

或者如果你用的是 Vite/Webpack 等 bundler,已经有清晰的项目结构:

{
  "compilerOptions": {
    "rootDir": ".",
    "outDir": "dist",
    "include": ["src"]
  }
}

检查方法:升级后跑一次 npx tsc --listEmittedFiles,看输出文件路径是否符合预期。

五、移除 baseUrl 隐式行为

变更内容

baseUrl 不再作为模块解析的查找根目录。

为什么会报错

很多人这样配置路径别名:

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@/*": ["*"],
      "@utils/*": ["utils/*"]
    }
  }
}

然后写:

import { helper } from '@/utils/helper';

升级后 TS 6 会警告:除非你用的是 paths 里明确声明的前缀,否则 baseUrl 不再兜底查找模块。

也就是说,如果你写了 import something from 'someModule.js',TS 5 会尝试在 baseUrl 下找文件,而 TS 6 不会。

怎么修

方案一:把 baseUrl 前缀合并到 paths(推荐)

{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"],
      "@utils/*": ["./src/utils/*"]
    }
  }
}

方案二:用 catch-all 保留旧行为(不常用)

{
  "compilerOptions": {
    "paths": {
      "*": ["./src/*"],
      "@utils/*": ["./src/utils/*"]
    }
  }
}

实际项目中最常见的修复

// 旧配置
{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@/*": ["*"]
    }
  }
}

// 新配置
{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

注意:路径别名前缀(@/*)必须和 paths 里的键对应。

六、升级实战清单

第一步:升级前检查

# 查看当前 TS 版本和配置
npx tsc --version

# 备份 tsconfig.json
cp tsconfig.json tsconfig.json.bak

第二步:安装 TS 6

npm install typescript@6 --save-dev

第三步:运行编译,统计问题数量

npx tsc --noEmit 2>&1 | tee tsc-errors.log

第四步:临时稳住

如果报错太多,先加过渡配置:

{
  "compilerOptions": {
    "ignoreDeprecations": "6.0",
    "strict": false,
    "types": ["*"]
  }
}

第五步:逐项修复

按优先级处理:

表格

优先级问题修复方案
P0@types/* 报错显式配置 types
P0隐式 any 报错先开 noImplicitAny
P1rootDir 输出路径问题配置 rootDir + include
P1baseUrl 路径别名合并前缀到 paths
P2strict 报错逐步开启各项检查

第六步:验证构建

# 本地构建
npm run build

# 检查输出文件
npx tsc --listEmittedFiles

第七步:CI 集成

# GitHub Actions 示例
- name: Type check
  run: npx tsc --noEmit

七、TS 7 展望:值得升级的理由

虽然 TS 6 带来了这些迁移成本,但站在更长的时间线上,这次升级是值得的:

1. 性能收益来自 TS 7

TS 7 基于 Go 重写的编译器,官方测试显示有的场景从 22 秒降到 4 秒。TS 6 清理的配置越干净,TS 7 迁移越顺畅。

2. 现代默认值更省心

  • strict: true 是业界最佳实践,越早开启越好
  • esnext 模块 + bundler 分辨率是主流方向
  • types 空数组能显著加快编译和编辑器响应

3. 新特性实用

  • using/await using:资源管理告别 try/finally
  • RegExp.escape:正则转义终于有标准 API
  • Map.getOrInsert:减少 Map 操作样板代码
  • #/ 子路径导入:路径别名更优雅

4. 生态同步

VS Code 1.119 已经开始全面迁移到 TS 7。新项目建议直接用 TS 6,默认值更现代。

总结

表格

变更旧默认值新默认值应对方式
strictfalsetrue逐项开启或先设 false
modulecommonjsesnext保持 commonjs 或迁移 ESM
types全部 @types[]显式声明需要的包
rootDir自动推断'.'配置 rootDir + include
baseUrl查找根目录不再兜底前缀合并到 paths

一句话建议:新项目直接上 TS 6,老项目把升级当个小项目来做,不要只改个版本号。

本文由AI辅助整理