首页 / TypeScript 入门教程 / 装饰器概述:双轨并行

TypeScript 入门教程

装饰器概述:双轨并行

本教程共 80 篇 · 第 67 篇 · 更新于 2026-08-10 · 约 10 分钟阅读

TypeScriptTypeScript 入门教程装饰器DecoratorexperimentalDecoratorsTC39Stage 3

本节目标:搞清楚 TypeScript 装饰器为什么有”两套”——一套是历史的 legacy 模式,一套是 TC39 标准化的 Stage 3 版本。理解它们的来龙去脉、语法差异、生态现状,以及你在实际项目中该怎么选。

装饰器是干什么的

装饰器(Decorator)是一种元编程语法。简单说,它允许你在不修改类原始代码的情况下,给类或类的成员”附加”额外行为。

// 一个最简单的装饰器
function log(target: any) {
  console.log("类被定义啦");
}

@log
class User {} // 控制台输出:类被定义啦

@log 放在 class User 上面,类定义时就会自动执行 log 函数。你不需要手动调用任何东西,装饰器替你做了”注入”这件事。

在 Angular、NestJS 这些框架里,你天天在写装饰器:

@Component({ ... })  // Angular 组件
@Injectable()        // NestJS 可注入服务
@Entity()            // TypeORM 实体

但你可能没意识到——这些框架用的装饰器,和 TypeScript 5.0 之后的标准装饰器,是两套完全不同的东西。

为什么有两套:一段 10 年的历史

事情要从 2014 年说起。

TypeScript 1.5 在 2015 年引入了装饰器支持。那时候 ECMAScript 标准委员会(TC39)也在讨论装饰器提案,TypeScript 就照着当时的提案草案实现了。使用方式很简单——在 tsconfig.json 里加上一行:

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

注意这个名字:experimental(实验性的)。TypeScript 团队非常清楚,TC39 的最终标准可能会变。

果不其然,TC39 的装饰器提案在接下来的 8 年里发生了翻天覆地的变化。2015 版草案、2016 版草案、2019 版草案……每一版都和前一个版本语法不兼容。TypeScript 一直保留着 2014 年的最初实现,也就是我们今天说的 legacy 装饰器

2022 年 3 月,TC39 装饰器提案终于进入 Stage 3(候选阶段),语法基本稳定。TypeScript 5.0(2023 年 3 月发布)第一时间实现了这套标准语法——不需要任何编译选项,开箱即用。

Note

所以今天 TypeScript 里有两套装饰器:

  • Legacy 装饰器:需要 experimentalDecorators: true,语法基于 2014 年 TC39 草案。
  • 标准装饰器:TC39 Stage 3,TS 5.0 起默认可用,不需要额外配置。

语法差异速览

两套装饰器的函数签名完全不同。先看一个直观对比。

Legacy 装饰器(类装饰器)

// 接收一个参数:类的构造函数
function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

标准装饰器(类装饰器)

// 接收两个参数:value(类本身)和 context(上下文对象)
function sealed(value: Function, context: ClassDecoratorContext) {
  // 通过 context.kind 判断装饰器类型
  if (context.kind === 'class') {
    Object.seal(value);
    Object.seal(value.prototype);
  }
}

区别不止这些。往下看:

对比维度Legacy 装饰器标准(Stage 3)装饰器
需要编译选项experimentalDecorators: true不需要(TS 5.0+)
类装饰器参数(constructor)(value, context)
方法装饰器参数(target, propertyKey, descriptor)(value, context)
属性装饰器有(拿不到值,功能受限)有(可返回初始化函数)
参数装饰器没有
accessor 关键字不存在auto-accessor
多个装饰器顺序由下往上执行由下往上执行(一致)
装饰器工厂支持支持

最关键的差异:两套装饰器不能混用。一个文件要么用 legacy,要么用标准。如果你在一个方法上写 @log,编译器必须根据文件级的配置来决定走哪套规则。

生态现状:大部分库还在用 legacy

截止 2026 年中,装饰器生态的格局很明确:

  • NestJS:完全基于 legacy 装饰器(@Controller@Injectable@Get 等)。因为标准装饰器不支持参数装饰器,而 NestJS 的依赖注入严重依赖参数装饰器,短期内无法迁移。
  • Angular:同样完全基于 legacy 装饰器(@Component@Input@Output 等),情况与 NestJS 类似。
  • TypeORM:基于 legacy 装饰器(@Entity@Column 等)。
  • class-validator / class-transformer:基于 legacy 装饰器。
  • 新项目 / 中小库:越来越多的新库开始支持或切换到标准装饰器。

简单总结:大型框架的迁移进度很慢。如果你是 Angular / NestJS 开发者,继续用 legacy 装饰器。如果是从零开始的小项目,可以考虑标准装饰器。

TypeScript 7.0 的兼容策略

TypeScript 7.0(2026 年 7 月发布)是 Go 原生移植的大版本(代号 Corsa)。虽然编译器从 JS 迁移到了 Go,但类型检查语义与 6.x 完全一致

对装饰器而言,7.0 的策略是:

  1. experimentalDecorators: true 仍然有效:legacy 装饰器不会被移除。
  2. 标准装饰器无需配置:和 5.0/6.x 一样,直接可用。
  3. emitDecoratorMetadata: true 仍然有效:继续支持 reflect-metadata 的元数据生成。
Tip

TypeScript 官方目前没有给出 legacy 装饰器的移除时间表。考虑到 Angular/NestJS 的生态体量,legacy 装饰器大概率会长期保留。你不需要急着迁移。

这两章怎么读

接下来五章的安排:

  • 第 68-69 章:详解 legacy 装饰器。哪怕你以后转向标准装饰器,Angular/NestJS 的项目里天天都要跟它打交道。
  • 第 70 章:详解 TC39 Stage 3 标准装饰器,包括 auto-accessor、上下文 API 等 legacy 没有的新特性。
  • 第 71 章:讲迁移策略和选型建议,结合最新的生态动态帮你做决策。

装饰器是高级特性。如果你刚开始学 TypeScript,建议先掌握前面章节的基础类型和类,再回头啃这部分。