TypeScript中的装饰器是什么,可以用于什么?
在TypeScript中,装饰器(Decorators)是一种特殊类型的声明,它们可以动态地添加属性或修改现有属性在类声明、方法、属性或参数上。装饰器提供了一种方式来向JavaScript对象添加标记,而不需要编写定义性代码或运行时开销。
1. 装饰器的基本概念
装饰器是一种函数,它允许你在不修改原始类定义的情况下,给类添加或修改行为。装饰器使用@符号后跟装饰器函数的调用。
function sealed(target: Function) {
target.prototype.sealed = true;
}
@sealed
class MyClass {
// ...
}
在这个例子中,我们定义了一个名为sealed的装饰器,它将一个sealed属性添加到了类MyClass的原型上。
2. 类装饰器
类装饰器用于修改类的结构。
function logClassName(target: Function) {
console.log(target.name);
}
@logClassName
class MyClass {
// ...
}
在这个例子中,当MyClass被定义时,logClassName装饰器会被调用,并且会打印出类名。
3. 方法装饰器
方法装饰器用于修改方法的行为。
function readOnly(target: any, propertyName: string) {
let privateName = '_' + propertyName;
target[privateName] = target[propertyName];
delete target[propertyName];
Object.defineProperty(target, propertyName, {
get: function() {
return this[privateName];
}
});
}
class MyClass {
@readOnly
public name: string;
}
在这个例子中,readOnly装饰器将name属性转换为只能通过getter方法访问的属性。
4. 访问器装饰器
访问器装饰器用于修改属性的getter和setter。
function limitValue(target: any, propertyName: string) {
let value = target[propertyName];
Object.defineProperty(target, propertyName, {
get: function() {
return value;
},
set: function(newValue: number) {
if (newValue > 100) {
value = 100;
} else {
value = newValue;
}
}
});
}
class Person {
@limitValue
age: number;
}
在这个例子中,limitValue装饰器限制了age属性的最大值不能超过100。
5. 参数装饰器
参数装饰器用于修改参数。
function required(target: any, propertyName: string, index: number) {
const parameters = target.constructor['parameters'];
const paramDescriptor = parameters.pop();
paramDescriptor.required = true;
parameters.push(paramDescriptor);
}
class Person {
constructor(@required name: string) {
this.name = name;
}
}
在这个例子中,required装饰器标记了构造函数中的name参数为必需的。
6. 装饰器的组合使用
装饰器可以组合使用,以在不同层面上修改类或成员。
function adminOnly(target: any, propertyName: string, descriptor: PropertyDescriptor) {
descriptor.writable = false;
}
function expensive(target: any, propertyName: string, descriptor: PropertyDescriptor) {
const method = descriptor.value;
descriptor.value = function(...args: any[]) {
if (this.isAdmin) {
console.log('Running an expensive method...');
return method.apply(this, args);
} else {
console.log('Access denied!');
}
};
}
class Service {
@expensive
@adminOnly
rebuildIndexes() {
// ...
}
}
在这个例子中,rebuildIndexes方法首先被expensive装饰器标记为昂贵的方法,然后被adminOnly装饰器标记为只有管理员才能修改的方法。