在 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. 总结
特性 | 描述 |
---|---|
类装饰器 | 应用于类构造函数,用于修改类的行为或添加元数据。 |
方法装饰器 | 应用于类的方法,用于修改方法的行为或添加元数据。 |
属性装饰器 | 应用于类的属性,用于添加元数据或修改属性的行为。 |
参数装饰器 | 应用于方法的参数,用于记录参数信息或添加元数据。 |
访问器装饰器 | 应用于存取器,用于修改存取器的行为或添加元数据。 |
装饰器工厂 | 返回装饰器函数的函数,允许动态配置装饰器。 |