TypeScript 装饰器
装饰器(Decorator)是一种特殊类型的声明,它能够被附加到类声明、方法、访问器、属性或参数上。装饰器使用 @expression
这种形式,expression
求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。
通过装饰器,我们可以修改类的行为,甚至可以实现 AOP(面向切面编程)。TypeScript 支持 5 种装饰器:
类装饰器
类装饰器在类声明之前被声明。类装饰器应用于类构造函数,可以用来监视、修改或替换类定义。
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class BugReport {
type = 'report';
title: string;
constructor(t: string) {
this.title = t;
}
}
上面代码中,@sealed
就是一个装饰器。它修改了BugReport
这个类的行为,为它加上了封印,阻止了添加新属性。
方法装饰器
方法装饰器声明在一个方法的声明之前。它会被应用到方法的属性描述符上,可以用来监视、修改或者替换方法定义。
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return 'Hello, ' + this.greeting;
}
}
上面代码中,@enumerable
是一个装饰器,它修改了greet
方法的描述对象,使得该方法不可枚举。
访问器装饰器
访问器装饰器声明在一个访问器的声明之前。访问器装饰器应用于访问器的属性描述符,可以用来监视、修改或替换一个访问器的定义。
function configurable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.configurable = value;
};
}
class Point {
private _x: number;
private _y: number;
constructor(x: number, y: number) {
this._x = x;
this._y = y;
}
@configurable(false)
get x() {
return this._x;
}
@configurable(false)
get y() {
return this._y;
}
}
上面代码中,@configurable
装饰器修改了x
和y
访问器的描述对象,使得它们不可配置。
属性装饰器
属性装饰器声明在一个属性声明之前。属性装饰器不能用在声明文件中,或者任何外部上下文里。
function format(formatString: string) {
return function (target: any, propertyKey: string) {
let value = this[propertyKey];
function getter() {
return formatString.replace('%s', value);
}
function setter(newVal: string) {
value = newVal;
}
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
});
};
}
class Greeter {
@format('Hello, %s')
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return this.greeting;
}
}
let g = new Greeter('world');
console.log(g.greet()); // "Hello, world"
上面代码中,@format
装饰器修改了greeting
属性的行为,使得它在获取和设置时都会进行格式化。
参数装饰器
参数装饰器声明在一个参数声明之前。参数装饰器应用于类构造函数或方法声明。
function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
throw new Error(`Argument ${parameterIndex} of ${propertyKey.toString()} is required`);
}
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet(@required name: string) {
return 'Hello ' + name + ', ' + this.greeting;
}
}