在 TypeScript 中,装饰器(Decorators)是一种特殊类型的声明,它允许你通过附加元数据或修改类、方法、属性等的行为来增强或改变它们。装饰器是一种元编程技术,通常用于通过注解方式来简化代码或增加功能,如日志记录、权限控制、缓存等。它是一个实验性特性,基于 ECMAScript 的装饰器提案,TypeScript 对它进行了支持。
装饰器在很多现代框架(如 Angular、NestJS 等)中广泛使用。通过装饰器,你可以对类、类的成员(方法、属性等)或者方法参数进行增强或修改。
1. 装饰器的基本概念
装饰器是一个 函数,它可以被附加到类、类的方法、属性、参数上,并在运行时修改或添加功能。
装饰器的语法:
@decoratorName
class MyClass {
// 类内容
}
装饰器的基本语法是在目标(类、方法、属性、参数)上使用 @
符号后接装饰器函数名。
2. 装饰器的种类
装饰器可以用在不同的目标上,每种装饰器有不同的功能和签名。TypeScript 支持以下几种常用的装饰器:
- 类装饰器(Class Decorators)
- 方法装饰器(Method Decorators)
- 属性装饰器(Property Decorators)
- 参数装饰器(Parameter Decorators)
2.1. 类装饰器(Class Decorators)
类装饰器应用于类定义上,它接受一个类构造函数作为参数。类装饰器通常用于修改类的行为,或为类添加一些元数据。
示例:类装饰器
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Person {
constructor(public name: string) {}
}
const person = new Person("Alice");
console.log(Object.isSealed(person)); // true
sealed
是一个类装饰器,它对Person
类进行了修改,使得类及其原型被“密封”。Object.seal()
方法将对象标记为不可添加或删除属性。
类装饰器的参数是构造函数,因此可以通过修改构造函数的行为来实现更多自定义功能。
2.2. 方法装饰器(Method Decorators)
方法装饰器应用于类的方法。它接受三个参数:
- 类的原型(
target
) - 方法名(
propertyKey
) - 方法的属性描述符(
descriptor
)
方法装饰器可以修改方法的行为,增加额外的功能,或者修改方法的属性描述符。
示例:方法装饰器
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Calling ${propertyKey} with arguments: ${args}`);
return originalMethod.apply(this, args);
};
}
class Calculator {
@log
add(a: number, b: number): number {
return a + b;
}
}
const calc = new Calculator();
calc.add(2, 3); // Calling add with arguments: [2, 3]
log
装饰器用于为add
方法添加日志功能,记录每次调用该方法时的参数。
2.3. 属性装饰器(Property Decorators)
属性装饰器用于类的属性上,它接受两个参数:
- 类的原型(
target
) - 属性名(
propertyKey
)
属性装饰器不能直接修改属性的值,但可以用于为属性添加元数据,或者通过修改类的原型实现类似的效果。
示例:属性装饰器
function logProperty(target: any, propertyKey: string) {
let value = target[propertyKey];
const getter = () => {
console.log(`Getting value of ${propertyKey}: ${value}`);
return value;
};
const setter = (newVal: any) => {
console.log(`Setting value of ${propertyKey}: ${newVal}`);
value = newVal;
};
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
});
}
class Person {
@logProperty
name: string;
constructor(name: string) {
this.name = name;
}
}
const person = new Person("Alice");
person.name = "Bob"; // Setting value of name: Bob
console.log(person.name); // Getting value of name: Bob
logProperty
装饰器为name
属性添加了 getter 和 setter,记录属性值的读取和修改。
2.4. 参数装饰器(Parameter Decorators)
参数装饰器应用于方法的参数上,它可以用于记录方法的参数元数据。参数装饰器接受三个参数:
- 类的原型(
target
) - 方法名(
propertyKey
) - 参数的索引(
parameterIndex
)
示例:参数装饰器
function logParameter(target: any, propertyKey: string, parameterIndex: number) {
console.log(`Method ${propertyKey} has parameter at index ${parameterIndex}`);
}
class Person {
greet(@logParameter name: string) {
console.log(`Hello, ${name}`);
}
}
const person = new Person();
person.greet("Alice"); // 输出: Method greet has parameter at index 0
logParameter
装饰器用于记录greet
方法的参数索引。
3. 装饰器的启用
装饰器是一个实验性特性,需要在 tsconfig.json
中启用 experimentalDecorators
选项才能使用。
启用装饰器
{
"compilerOptions": {
"experimentalDecorators": true
}
}
4. 装饰器工厂
有时我们希望为装饰器传递参数,可以通过 装饰器工厂 来实现。装饰器工厂是返回装饰器的函数,通常用于自定义装饰器的行为。
示例:装饰器工厂
function addPrefix(prefix: string) {
return function (target: any, propertyKey: string) {
console.log(`Adding prefix: ${prefix} to ${propertyKey}`);
};
}
class Person {
@addPrefix("Mr.")
name: string;
constructor(name: string) {
this.name = name;
}
}
addPrefix
是一个装饰器工厂,它返回一个装饰器,该装饰器在应用时会添加前缀。
5. 装饰器的组合
多个装饰器可以同时应用于一个目标,装饰器按声明的顺序从下到上依次执行。
示例:装饰器组合
function decoratorA(target: any) {
console.log("Decorator A");
}
function decoratorB(target: any) {
console.log("Decorator B");
}
@decoratorA
@decoratorB
class MyClass {}
输出:
Decorator B
Decorator A
- 装饰器的执行顺序是从下往上,先执行
decoratorB
,再执行decoratorA
。
6. 装饰器的应用场景
装饰器在许多框架和库中都有广泛应用,常见的应用场景包括:
- Angular:用于定义组件、指令、服务等。
- NestJS:用于路由处理、请求体验证、身份验证等。
- TypeORM:用于定义实体模型、字段映射、索引等。
- 日志记录:为方法添加日志功能。
- 权限控制:为方法添加权限验证。
- 性能监控:记录方法执行时间。
7. 总结
- 装饰器是 TypeScript 中的一个实验性特性,用于对类、方法、属性、参数等进行增强或修改。
- 装饰器可以用来简化和规范代码,如日志记录、权限控制、缓存等。
- 装饰器分为类装饰器、方法装饰器、属性装饰器、参数装饰器等类型。
- 需要通过配置
experimentalDecorators
选项来启用装饰器。 - 装饰器是一个强大的元编程工具,广泛应用于现代框架和库中。
装饰器为 TypeScript 提供了更加灵活和可扩展的编程方式,特别适用于注解驱动的开发。