TypeScript装饰器-简洁版
TypeScript 中的装饰器(Decorators)是一种特殊类型的声明,它能够被附加到类声明、方法、访问器、属性或参数上。装饰器使用 @expression
这种形式,其中 expression
必须计算为一个函数,该函数会在运行时被调用。
装饰器的主要用途是修改或增强类、属性、方法或参数的行为。TypeScript 装饰器是实验性功能,需要在 tsconfig.json
文件中启用 experimentalDecorators
选项才能使用。
以下是装饰器的几种常见用法和示例:
1. 类装饰器
类装饰器用于修饰类本身。它接收一个参数,即类的构造函数。
示例:添加日志功能
function Logger(constructor: Function) {console.log("Logging...");console.log(constructor);
}@Logger
class Person {name = "John";constructor() {console.log("Creating person object...");}
}const person = new Person();
console.log(person);
输出:
Logging...
[Function: Person]
Creating person object...
Person { name: 'John' }
示例:修改类的行为
function WithTemplate(template: string, hookId: string) {return function(constructor: any) {const hookEl = document.getElementById(hookId);const p = new constructor();if (hookEl) {hookEl.innerHTML = template;hookEl.querySelector("h1")!.textContent = p.name;}};
}@WithTemplate("<h1>Person Object</h1>", "app")
class Person {name = "John";constructor() {console.log("Creating person object...");}
}
HTML:
<div id="app"></div>
输出:
在页面中显示:
<h1>John</h1>
2. 方法装饰器
方法装饰器用于修饰类中的方法。它接收三个参数:
- 对于静态成员,是类的构造函数;对于实例成员,是类的原型对象。
- 成员的名称。
- 成员的属性描述符。
示例:方法装饰器
function Log(target: any, propertyName: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {console.log(`Logging the call of ${propertyName}`);console.log(args);const result = originalMethod.apply(this, args);console.log(result);return result;};
}class Product {title: string;private _price: number;constructor(t: string, p: number) {this.title = t;this._price = p;}@LoggetPriceWithTax(tax: number) {return this._price * (1 + tax);}
}const product = new Product("Book", 19.99);
console.log(product.getPriceWithTax(0.2));
输出:
Logging the call of getPriceWithTax
[0.2]
23.988
23.988
3. 访问器装饰器
访问器装饰器用于修饰类中的访问器(getter 或 setter)。它接收两个参数:
- 对于静态成员,是类的构造函数;对于实例成员,是类的原型对象。
- 成员的名称。
示例:访问器装饰器
function Log(target: any, propertyName: string) {console.log("Property decorator!");console.log(target);console.log(propertyName);
}class Product {private _price: number;constructor(p: number) {this._price = p;}@Logget price() {return this._price;}@Logset price(value: number) {this._price = value;}
}const product = new Product(10);
console.log(product.price);
product.price = 20;
输出:
Property decorator!
Product {}
price
Property decorator!
Product {}
price
10
4. 参数装饰器
参数装饰器用于修饰类方法的参数。它接收三个参数:
- 对于静态成员,是类的构造函数;对于实例成员,是类的原型对象。
- 成员的名称。
- 参数的索引。
示例:参数装饰器
function Log(target: any, propertyName: string, index: number) {console.log("Parameter decorator!");console.log(target);console.log(propertyName);console.log(index);
}class Product {title: string;private _price: number;constructor(t: string, p: number) {this.title = t;this._price = p;}getPriceWithTax(@Log tax: number) {return this._price * (1 + tax);}
}const product = new Product("Book", 19.99);
console.log(product.getPriceWithTax(0.2));
输出:
Parameter decorator!
Product {}
getPriceWithTax
0
23.988
5. 组合使用装饰器
装饰器可以组合使用,但需要注意执行顺序:
- 参数装饰器先执行。
- 方法装饰器次之。
- 访问器装饰器再次。
- 最后是类装饰器。
示例:组合装饰器
function ClassDecorator(constructor: Function) {console.log("Class decorator");
}function MethodDecorator(target: any, propertyName: string, descriptor: PropertyDescriptor) {console.log("Method decorator");
}function ParameterDecorator(target: any, propertyName: string, index: number) {console.log("Parameter decorator");
}@ClassDecorator
class Product {constructor() {}@MethodDecoratormethod(@ParameterDecorator param: string) {}
}
输出:
Parameter decorator
Method decorator
Class decorator
6. 装饰器工厂
装饰器工厂是一个返回装饰器的函数,可以接收参数。
示例:装饰器工厂
function Log(prefix: string) {return function (target: any, propertyName: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {console.log(`${prefix}: Logging the call of ${propertyName}`);console.log(args);const result = originalMethod.apply(this, args);console.log(result);return result;};};
}class Product {title: string;private _price: number;constructor(t: string, p: number) {this.title = t;this._price = p;}@Log("PRODUCT")getPriceWithTax(tax: number) {return this._price * (1 + tax);}
}const product = new Product("Book", 19.99);
console.log(product.getPriceWithTax(0.2));
输出:
PRODUCT: Logging the call of getPriceWithTax
[0.2]
23.988
23.988
7. 装饰器的限制
- 装饰器是实验性功能,需要在
tsconfig.json
中启用experimentalDecorators
。 - 装饰器的执行顺序需要注意,参数装饰器先执行,方法装饰器次之,访问器装饰器再次,最后是类装饰器。
- 装饰器不能直接修改类的构造函数或方法的返回值,需要通过返回一个新的构造函数或方法来实现。
总结
装饰器是 TypeScript 中一个非常强大的功能,可以用来增强类、方法、属性和参数的行为。通过合理使用装饰器,可以实现诸如日志记录、权限检查、性能监控等功能,而无需修改原始代码。