0Pricing
Frontend Academy · 课时

装饰器与元数据

启用实验性装饰器,编写类、方法和属性装饰器,并使用 reflect-metadata 实现依赖注入模式。

装饰器与元数据 是 CoddyKit 上的免费 Frontend Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Frontend Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Frontend Academy 课程共包含 4 节课。

什么是装饰器

装饰器是在定义时修改类、方法、属性或参数的函数。Angular、NestJS、TypeORM 和基于类的 MobX 大量使用装饰器。

装饰器语法

在类、方法、属性或参数前加上 @DecoratorName。装饰器函数会在类定义时运行。

@Component({ selector: 'app-root' })
export class AppComponent {
  @Input() title: string;

  @HostListener('click')
  onClick() {
    console.log('clicked');
  }
}

启用装饰器

在 tsconfig.json 中启用实验性标志。新的 ECMAScript 第 3 阶段装饰器(TypeScript 5.0+)不需要此标志,但语义有所不同。

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

类装饰器

它会接收构造函数作为参数,并可以替换、包装或扩展类。

function Singleton<T extends { new (...a: any[]): {} }>(target: T) {
  let instance: T;
  return class extends target {
    constructor(...args: any[]) {
      if (!instance) instance = new target(...args) as T;
      return instance;
    }
  };
}

@Singleton
class Logger { /* ... */ }

方法装饰器

它会接收(目标、键、描述符)。您可以用它包装方法,例如记录调用。

function Log(target: any, key: string, descriptor: PropertyDescriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`[${key}]`, args);
    return original.apply(this, args);
  };
}

class Service {
  @Log
  greet(name: string) { return `Hello ${name}`; }
}

属性装饰器

它会接收(目标、键)。通常与 reflect-metadata 一起使用,用于注册属性相关信息。

function Required(target: any, key: string) {
  const existing = Reflect.getMetadata('required', target) || [];
  Reflect.defineMetadata('required', [...existing, key], target);
}

class User {
  @Required name: string;
  @Required email: string;
}

参数装饰器

它会接收(目标、键、parameterIndex)。用于依赖注入,记录哪些参数需要哪些服务。

function Inject(token: string) {
  return function (target: any, key: string, index: number) {
    const existing = Reflect.getMetadata('inject', target, key) || {};
    existing[index] = token;
    Reflect.defineMetadata('inject', existing, target, key);
  };
}

class UserService {
  constructor(@Inject('Database') db: Database) {}
}

reflect-metadata

reflect-metadata 是一个 polyfill,允许装饰器读取和写入类的元数据。Angular DI 和许多 ORM 都需要它。

npm install reflect-metadata

// main.ts (entry point):
import 'reflect-metadata';

import { Reflect } from 'reflect-metadata';
Reflect.defineMetadata('key', 'value', target);
Reflect.getMetadata('key', target); // 'value'

装饰器工厂

工厂会返回一个装饰器,用于传入参数。

function Component(config: { selector: string }) {
  return function (target: any) {
    target.selector = config.selector;
  };
}

@Component({ selector: 'app-root' })
class AppComponent {}

验证应用场景

将属性装饰器与验证函数结合起来,即可构建一个小型验证库。

// Decorator records that a field is required:
function Required(target: any, key: string) {
  const fields = Reflect.getMetadata('required', target) || [];
  Reflect.defineMetadata('required', [...fields, key], target);
}

class User {
  @Required name!: string;
  @Required email!: string;
}

function validate(obj: any): string[] {
  const required: string[] = Reflect.getMetadata('required', obj) || [];
  return required.filter(k => obj[k] == null);
}

第 3 阶段装饰器(TC39)

标准化的装饰器(TS 5.0+,Node 22+ 在启用标志后支持)具有不同的签名。它们不需要实验性标志,也不需要 reflect-metadata。

何时使用装饰器

在框架提供装饰器的地方使用它们(Angular、NestJS、TypeORM)。不要在普通前端代码中自行创建装饰器,因为它们会增加复杂性,并使代码依赖特定的运行时行为。

快速检查

要使用带有元数据反射的旧版(实验性)装饰器,必须启用哪些 tsconfig 标志?

回顾:装饰器

装饰器会在定义时修改类、方法、属性或参数。请启用 experimentalDecorators 和 emitDecoratorMetadata。类、方法、属性和参数装饰器的签名各不相同。reflect-metadata 用于存储元数据;工厂用于传入参数。Angular、NestJS 和 TypeORM 大量使用装饰器。第 3 阶段装饰器(TS 5+)是未来的发展方向,不需要任何标志。

常见问题解答

「装饰器与元数据」课时是免费的吗?

是的 — 「装饰器与元数据」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Frontend Academy 课程的其余内容,请升级到 CoddyKit PRO。 Frontend Academy 课程共包含 4 节课。

「装饰器与元数据」这节课中我会学到什么?

启用实验性装饰器,编写类、方法和属性装饰器,并使用 reflect-metadata 实现依赖注入模式。 你通过在浏览器中直接运行的动手代码来练习 Frontend Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Frontend Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Frontend Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「装饰器与元数据」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Frontend Academy 课中编写并运行代码吗?

能。每节 Frontend Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 模板字面量类型
  2. 装饰器与元数据
  3. TypeScript 与 React:FC 泛型钩子
  4. 严格模式与消除 any
← 返回 Frontend Academy