在 TypeScript 中,裝飾器(Decorators) 是一種特殊的聲明,用于為類、類成員(屬性、方法、訪問器)、方法參數或整個類添加元數據或修改其行為。裝飾器是 JavaScript 和 TypeScript 的實驗性特性,廣泛應用于框架開發(如 Angular)和元編程場景。
1. 啟用裝飾器
在 TypeScript 中,默認情況下裝飾器是禁用的。要啟用裝飾器支持,需要在 tsconfig.json
文件中設置以下選項:
{"compilerOptions": {"experimentalDecorators": true}
}
2. 裝飾器的基本概念
(1) 定義
- 裝飾器是一個函數,它接收一個目標對象作為參數,并可以對其進行修改或擴展。
- 裝飾器通過
@
符號應用到目標上。
(2) 語法
function Decorator(target: any): void {// 修改或擴展 target 的行為
}@Decorator
class MyClass {}
3. 類裝飾器
(1) 定義
- 類裝飾器應用于類構造函數本身。
- 它可以用來修改類的行為或添加元數據。
(2) 示例
function LogClass(constructor: Function) {console.log(`Class ${constructor.name} has been defined.`);
}@LogClass
class User {name: string;constructor(name: string) {this.name = name;}
}const user = new User("Alice"); // 輸出 "Class User has been defined."
在這里:
LogClass
是一個類裝飾器,用于記錄類的定義。
4. 方法裝飾器
(1) 定義
- 方法裝飾器應用于類的方法。
- 它可以用來修改方法的行為或添加元數據。
(2) 示例
function LogMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {console.log(`Calling method '${propertyKey}' with arguments: ${args}`);return originalMethod.apply(this, args);};
}class Calculator {@LogMethodadd(a: number, b: number): number {return a + b;}
}const calculator = new Calculator();
console.log(calculator.add(2, 3));
// 輸出:
// Calling method 'add' with arguments: 2,3
// 5
在這里:
LogMethod
是一個方法裝飾器,用于記錄方法調用及其參數。
5. 屬性裝飾器
(1) 定義
- 屬性裝飾器應用于類的屬性。
- 它可以用來添加元數據或修改屬性的行為。
(2) 示例
function LogProperty(target: any, propertyKey: string) {let value: any;const getter = function () {console.log(`Getting value of '${propertyKey}'`);return value;};const setter = function (newValue: any) {console.log(`Setting value of '${propertyKey}' to ${newValue}`);value = newValue;};Object.defineProperty(target, propertyKey, {get: getter,set: setter,enumerable: true,configurable: true,});
}class User {@LogPropertyname: string;constructor(name: string) {this.name = name;}
}const user = new User("Alice");
console.log(user.name); // 輸出 "Getting value of 'name'" 和 "Alice"
user.name = "Bob"; // 輸出 "Setting value of 'name' to Bob"
在這里:
LogProperty
是一個屬性裝飾器,用于記錄屬性的訪問和修改。
6. 參數裝飾器
(1) 定義
- 參數裝飾器應用于方法的參數。
- 它可以用來添加元數據或記錄參數信息。
(2) 示例
function LogParameter(target: any, propertyKey: string | symbol, parameterIndex: number) {console.log(`Parameter at index ${parameterIndex} in method '${String(propertyKey)}' is decorated.`);
}class Calculator {add(@LogParameter a: number, @LogParameter b: number): number {return a + b;}
}const calculator = new Calculator();
calculator.add(2, 3);
// 輸出:
// Parameter at index 0 in method 'add' is decorated.
// Parameter at index 1 in method 'add' is decorated.
在這里:
LogParameter
是一個參數裝飾器,用于記錄方法參數的索引和名稱。
7. 訪問器裝飾器
(1) 定義
- 訪問器裝飾器應用于類的存取器(getter 和 setter)。
- 它可以用來修改存取器的行為或添加元數據。
(2) 示例
function LogAccessor(target: any, propertyKey: string, descriptor: PropertyDescriptor) {const originalGetter = descriptor.get;const originalSetter = descriptor.set;descriptor.get = function () {console.log(`Getting value of '${propertyKey}'`);return originalGetter?.apply(this);};descriptor.set = function (value: any) {console.log(`Setting value of '${propertyKey}' to ${value}`);originalSetter?.apply(this, [value]);};
}class User {private _name: string;constructor(name: string) {this._name = name;}@LogAccessorget name(): string {return this._name;}set name(value: string) {this._name = value;}
}const user = new User("Alice");
console.log(user.name); // 輸出 "Getting value of 'name'" 和 "Alice"
user.name = "Bob"; // 輸出 "Setting value of 'name' to Bob"
在這里:
LogAccessor
是一個訪問器裝飾器,用于記錄存取器的訪問和修改。
8. 裝飾器工廠
裝飾器工廠是一個返回裝飾器函數的函數,允許傳遞參數以動態配置裝飾器。
示例
function Log(message: string) {return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {console.log(`${message}: Calling method '${propertyKey}' with arguments: ${args}`);return originalMethod.apply(this, args);};};
}class Calculator {@Log("Debug Info")add(a: number, b: number): number {return a + b;}
}const calculator = new Calculator();
calculator.add(2, 3);
// 輸出:
// Debug Info: Calling method 'add' with arguments: 2,3
在這里:
Log
是一個裝飾器工廠,允許傳遞自定義消息。
9. 實際應用場景
(1) 日志記錄
- 使用裝飾器記錄方法調用、參數和返回值。
(2) 權限控制
- 使用裝飾器檢查用戶權限,限制對某些方法的訪問。
示例
function RequireRole(role: string) {return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {if (role === "admin") {return originalMethod.apply(this, args);} else {throw new Error("Permission denied");}};};
}class AdminPanel {@RequireRole("admin")deleteUser(userId: number): void {console.log(`Deleting user with ID ${userId}`);}
}const panel = new AdminPanel();
panel.deleteUser(123); // 如果 role 不是 "admin",會拋出錯誤
10. 總結
特性 | 描述 |
---|---|
類裝飾器 | 應用于類構造函數,用于修改類的行為或添加元數據。 |
方法裝飾器 | 應用于類的方法,用于修改方法的行為或添加元數據。 |
屬性裝飾器 | 應用于類的屬性,用于添加元數據或修改屬性的行為。 |
參數裝飾器 | 應用于方法的參數,用于記錄參數信息或添加元數據。 |
訪問器裝飾器 | 應用于存取器,用于修改存取器的行為或添加元數據。 |
裝飾器工廠 | 返回裝飾器函數的函數,允許動態配置裝飾器。 |