目录

TypeScript 5.x 实战:新特性与迁移避坑

先说要不要升

TypeScript 升级政策是:每个 major 版本支持 24 个月。

目前(2025年):

  • TS 5.0+ 是主流
  • TS 4.x 进入维护模式
  • TS 5.6 是最新稳定版

建议:新项目直接用最新版,老项目逐 minor 版本升级,不要跳版本。

5.0: 装饰器 (Decorators)

最重要的变化:装饰器终于标准化了。

// TS 5.0 装饰器语法
function logged(target: any, context: ClassMethodDecoratorContext) {
  const methodName = String(context.name);
  return function (this: any, ...args: any[]) {
    console.log(`Calling ${methodName}`);
    return target.apply(this, args);
  };
}

class Calculator {
  @logged
  add(a: number, b: number) {
    return a + b;
  }
}

这是 ECMAScript 正式的装饰器提案,跟之前用 experimentalDecorators 不一样。

对 React 项目的影响

// 以前:需要 babel 配置
// 现在:TypeScript 原生支持
function withAuth(target: any, context: ClassMethodDecoratorContext) {
  return function (this: any, ...args: any[]) {
    if (!currentUser) {
      throw new Error('Unauthorized');
    }
    return target.apply(this, args);
  };
}

class Dashboard {
  @withAuth
  async fetchData() {
    // 只有登录用户能访问
  }
}

5.1: 独立的类型推导改进

// 5.1 之前:return type 必须显式写
function createElement(tag: string): HTMLElement {
  return document.createElement(tag);
}

// 5.1 支持:显式返回 undefined
function maybeCreateElement(tag: string): HTMLElement | undefined {
  if (!tag) return undefined;
  return document.createElement(tag);
}

// 5.1 支持:泛型函数可以返回不同类型
function find<T>(arr: T[], predicate: (item: T) => boolean): T | undefined {
  return arr.find(predicate);
}

这个改进让很多以前要写复杂类型 hack 的场景变得简单。

5.2: using 和 Explicit Resource Management

类似 Python 的 with 语句:

// 5.2 新增:using 声明
function readFile(path: string) {
  const file = using f = openFile(path);  // 自动管理资源
  return f.read();
}  // file 自动关闭

// 配合 Symbol.dispose
class DatabaseConnection {
  [Symbol.dispose]() {
    this.close();
  }
}

function query() {
  using conn = new DatabaseConnection();
  conn.execute("SELECT * FROM users");
}  // 自动关闭连接

对需要手动管理连接/文件/锁的场景很有用,减少 memory leak。

5.4: NoInfer utility type

// 5.4 新增 NoInfer
function createSignal<T>(value: T, defaultValue: NoInfer<T>) {
  return { value: value ?? defaultValue };
}

// 以前这样写会 type error
createSignal("hello", "world"); // T 被推断为 "hello",但 defaultValue 也是 string,没问题

// NoInfer 防止类型被进一步推断
// 用于 API 设计中强制某些参数用字面量类型

5.5: 推断的 Predicates 类型改进

// 5.5 之前:array.filter 后要 cast
const users = [{ name: "Alice" }, { name: "Bob" }, null];
const names = users
  .filter((u): u is NonNullable<typeof u> => u !== null)
  .map(u => u.name);

// 5.5:TypeScript 自动推断 predicate
const names2 = users
  .filter(u => u !== null)  // TS 自动推断返回类型
  .map(u => u.name);  // u 现在是 { name: string },不用手动写类型断言

这个改进让代码简洁很多。

迁移注意事项

逐版本迁移

# 不要跳版本
tsc --version
# 5.5.4 → 迁移到 5.6

# 逐 minor 升级
npm install [email protected]
# 跑测试
npm test
# 确认没问题再继续

常见 breaking changes

  1. noImplicitAny 更严格:有些隐式 any 现在报错
  2. useDefineForClassFields:和 ES2022 语义对齐,可能影响 class field 行为
  3. isolatedModules:每个文件必须是独立可编译的

检查 tsconfig

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "isolatedModules": true
  }
}

总结

TypeScript 5.x 最有价值的新特性:

版本 特性 实用度
5.0 标准装饰器 ⭐⭐⭐⭐ 前端必用
5.1 类型推导改进 ⭐⭐⭐ 减少类型 hack
5.2 using 资源管理 ⭐⭐⭐ 文件/连接管理
5.4 NoInfer ⭐⭐ API 设计用
5.5 Predicate 自动推断 ⭐⭐⭐⭐ 简化 filter/map

建议:保持 minor 版本更新,每次更新只升一个版本,跑测试确认。