第9章:装饰器
类装饰器、方法装饰器、属性装饰器
装饰器(Decorator)是 TypeScript 中一种特殊的声明,它可以附加到类、方法、属性或参数上,用于修改或扩展其行为。装饰器通过 @expression 的语法形式应用,其中 expression 必须是一个函数,它会在运行时被调用,并接收特定的参数。本节将详细介绍类装饰器、方法装饰器和属性装饰器的用法和实现原理。
类装饰器(Class Decorator)
类装饰器应用于类的构造函数,用于观察、修改或替换类定义。它接收一个参数:类的构造函数。
基本语法
function classDecorator(constructor: Function) {
// 修改或扩展类
}
@classDecorator
class MyClass {}
示例:添加元数据
function logClass(target: Function) {
console.log(`Class ${target.name} is decorated.`);
}
@logClass
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
}
// 输出:Class Person is decorated.
示例:修改类
类装饰器可以返回一个新的构造函数来替换原始类:
function extendClass<T extends { new (...args: any[]): {} }>(constructor: T) {
return class extends constructor {
newProperty = "New Property";
};
}
@extendClass
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
}
const cat = new Animal("Cat");
console.log((cat as any).newProperty); // 输出:New Property
方法装饰器(Method Decorator)
方法装饰器应用于类的方法,用于修改或观察方法的定义。它接收三个参数:
- 类的原型(或构造函数静态方法)。
- 方法名称。
- 方法的属性描述符(
PropertyDescriptor)。
基本语法
function methodDecorator(
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
// 修改方法行为
}
class MyClass {
@methodDecorator
myMethod() {}
}
示例:日志装饰器
function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling ${propertyKey} with args: ${JSON.stringify(args)}`);
return originalMethod.apply(this, args);
};
}
class Calculator {
@logMethod
add(a: number, b: number) {
return a + b;
}
}
const calc = new Calculator();
calc.add(2, 3); // 输出:Calling add with args: [2,3]
示例:拦截方法调用
function delay(ms: number) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
setTimeout(() => {
originalMethod.apply(this, args);
}, ms);
};
};
}
class Greeter {
@delay(1000)
greet(name: string) {
console.log(`Hello, ${name}!`);
}
}
const greeter = new Greeter();
greeter.greet("Alice"); // 1秒后输出:Hello, Alice!
属性装饰器(Property Decorator)
属性装饰器应用于类的属性,用于观察或修改属性的行为。它接收两个参数:
- 类的原型(或构造函数静态属性)。
- 属性名称。
基本语法
function propertyDecorator(target: any, propertyKey: string) {
// 修改或观察属性
}
class MyClass {
@propertyDecorator
myProperty: string;
}
示例:属性只读装饰器
function readOnly(target: any, propertyKey: string) {
Object.defineProperty(target, propertyKey, {
writable: false,
});
}
class User {
@readOnly
id: number;
constructor(id: number) {
this.id = id;
}
}
const user = new User(1);
user.id = 2; // 报错:Cannot assign to 'id' because it is read-only.
示例:属性监听
function watchProperty(target: any, propertyKey: string) {
let value = target[propertyKey];
Object.defineProperty(target, propertyKey, {
get: () => value,
set: (newValue) => {
console.log(`Property ${propertyKey} changed from ${value} to ${newValue}`);
value = newValue;
},
});
}
class Product {
@watchProperty
price: number;
constructor(price: number) {
this.price = price;
}
}
const product = new Product(100);
product.price = 200; // 输出:Property price changed from 100 to 200
总结
- 类装饰器:用于修改或替换类定义,接收构造函数作为参数。
- 方法装饰器:用于修改方法行为,接收目标对象、方法名和属性描述符。
- 属性装饰器:用于观察或修改属性,接收目标对象和属性名。
装饰器为 TypeScript 提供了强大的元编程能力,广泛应用于框架(如 Angular、NestJS)和工具库中。在下一节中,我们将学习如何通过装饰器工厂进一步定制装饰器的行为。
