TypeScript 中的装饰器

TypeScript 中的装饰器

本文解释了 TypeScript 中的装饰器。

YouTube Video

TypeScript 中的装饰器

TypeScript 装饰器是一种为类、方法、访问器、属性或参数添加额外功能或行为的机制。装饰器是增强代码可读性和可重用性的强大工具。

装饰器的基础

装饰器是一种为类或类成员注入额外功能的函数。装饰器是在 TypeScript 1.5 中引入的,并已被提议纳入 ECMAScript 标准。

1{
2  "compilerOptions": {
3    "experimentalDecorators": true
4  }
5}
  • 要使用装饰器,您需要在 tsconfig.json 文件中启用 experimentalDecorators 选项。

装饰器的类型

在 TypeScript 中,您可以使用以下五种装饰器。

  • 类装饰器 应用于类的装饰器。
  • 方法装饰器 应用于类方法的装饰器。
  • 访问器装饰器 应用于类属性的 getter 或 setter 的装饰器。
  • 属性装饰器 应用于类属性的装饰器。
  • 参数装饰器 应用于方法参数的装饰器。

类装饰器

类装饰器是应用于类的装饰器。类装饰器写在类定义的正上方,可以访问类的构造函数。它们主要用于更改类的行为或添加元数据。

 1function Logger(constructor: Function) {
 2    console.log(`Class ${constructor.name} is being constructed`);
 3}
 4
 5@Logger
 6class Person {
 7    constructor(public name: string) {}
 8}
 9
10const person = new Person('John');
11// Output: Class Person is being constructed

在此示例中,Logger 装饰器应用于类,并在类初始化时在控制台中显示一条消息。

方法装饰器

方法装饰器应用于类方法,可以更改方法的调用和行为。方法装饰器接收三个参数。

  1. 类的原型
  2. 方法的名称
  3. 方法的属性描述符
 1function LogExecutionTime(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
 2    const originalMethod = descriptor.value;
 3
 4    descriptor.value = function (...args: any[]) {
 5        console.time(propertyKey);
 6        const result = originalMethod.apply(this, args);
 7        console.timeEnd(propertyKey);
 8        return result;
 9    };
10}
11
12class MathOperations {
13  @LogExecutionTime
14  add(a: number, b: number): number {
15    return a + b;
16  }
17}
18
19const math = new MathOperations();
20math.add(2, 3);
21// Output: add: 0.000ms (execution time is displayed)

在此示例中,将 LogExecutionTime 装饰器应用于方法,并记录方法的执行时间。

访问器装饰器

访问器装饰器应用于类属性的 gettersetter。它们在修改属性值时用于添加行为。

 1function LogAccess(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
 2    const originalGet = descriptor.get;
 3    const originalSet = descriptor.set;
 4
 5    if (originalGet) {
 6        descriptor.get = function () {
 7            console.log(`Getter called for ${propertyKey}`);
 8            return originalGet.call(this);
 9        };
10    }
11
12    if (originalSet) {
13        descriptor.set = function (value: any) {
14            console.log(`Setter called for ${propertyKey} with value: ${value}`);
15            originalSet.call(this, value);
16        };
17    }
18}
19
20class Car {
21    private _speed: number = 0;
22
23    @LogAccess
24    get speed() {
25        return this._speed;
26    }
27
28    set speed(value: number) {
29        this._speed = value;
30    }
31}
32
33const car = new Car();
34car.speed = 120;               // Setter called for speed with value: 120
35console.log(car.speed);       // Getter called for speed → 120

在这个例子中,当调用 gettersetter 时,使用了一个访问器装饰器来记录输出。

属性装饰器

属性装饰器应用于类属性,但不能直接更改属性的值或行为。它们用于获取属性的元数据。

 1function Readonly(target: any, propertyKey: string) {
 2    Object.defineProperty(target, propertyKey, {
 3        writable: false
 4    });
 5}
 6
 7class Book {
 8    @Readonly
 9    title: string = "TypeScript Guide";
10}
11
12const book = new Book();
13book.title = "New Title"; // Error: Cannot assign to read only property 'title'

在此示例中,将 Readonly 装饰器应用于 title 属性,使该属性成为只读。

参数装饰器

参数装饰器应用于方法的参数。它们通常用于存储元数据或验证参数。装饰器接收三个参数。

  1. 类的原型
  2. 方法的名称
  3. 参数索引
 1function LogParameter(target: any, propertyKey: string, parameterIndex: number) {
 2    console.log(`Parameter at index ${parameterIndex} in method ${propertyKey} was decorated.`);
 3}
 4
 5class User {
 6    greet(@LogParameter message: string) {
 7        console.log(message);
 8    }
 9}
10
11const user = new User();
12user.greet('Hello!');
13// Output: Parameter at index 0 in method greet was decorated.

在此示例中,将 LogParameter 装饰器应用于 greet 方法的第一个参数,当调用此方法时,会记录该参数已被装饰。

装饰器的实际示例

装饰器广泛用于例如 Angular 这样的框架,尤其是在依赖注入和元数据定义方面。例如,可以使用 @Component 装饰器来定义类似如下的 Angular 组件。

1@Component({
2    selector: 'app-root',
3    template: '<h1>Hello World</h1>',
4})
5export class AppComponent {}

因此,装饰器通常作为框架和库的核心部分使用,有助于保持代码简洁明了。

装饰器总结

TypeScript 装饰器是强大的工具,可以灵活地为类、方法和属性添加功能。使用自定义装饰器可以提高代码的可维护性和可复用性,从而实现更高的抽象。装饰器在像Angular和NestJS这样的框架中起着重要作用,理解它们有助于深入了解这些框架的工作原理。

您可以在我们的YouTube频道上使用Visual Studio Code跟随上述文章进行学习。 请也查看我们的YouTube频道。

YouTube Video