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