TypeScript 装饰器
装饰器是一种特殊的声明,可以应用于类、方法、存取器、属性或参数。装饰器只是函数,其前缀是 @expression 符号,其中 expression 必须评估为在运行时将使用关于装饰声明的信息调用的函数。
注意:装饰器是一个实验性功能,提议用于 ES7。一些 JavaScript 框架,包括 Angular 2,已经在使用装饰器。装饰器可能会在未来版本中更改。
为了启用对装饰器的实验性支持,我们必须在 命令行 或 tsconfig.json 中启用 experimentalDecorators 编译选项:
命令行
$tsc --target ES5 --experimentalDecorators
tsconfig.json
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}
目的
TypeScript装饰器的目的是以声明性的方式向现有代码添加注释和元数据。
装饰器工厂
为了自定义装饰器应用到声明的方式,我们可以编写一个装饰器工厂。装饰器工厂是一个返回表达式的函数,该表达式在运行时由装饰器调用。
装饰器工厂可以以以下方式编写:
function color(value: string) { // this is the decorator factory
return function (target) { // this is the decorator
// do something with 'target' and 'value'...
}
}
装饰器组合
我们可以将多个装饰器应用于一个声明上。以下示例有助于理解。
在单行上
@f @g x
分行显示
@f
@g
x
装饰器的类型
TypeScript使用以下类型的装饰器:
- 类装饰器
- 方法装饰器
- 访问器装饰器
- 属性装饰器
- 参数装饰器
1. 类装饰器
类装饰器定义在类声明之前,它描述了类的行为。类装饰器应用于类的构造函数。类装饰器可用于观察、修改或替换类定义。如果类装饰器返回一个值,它将用给定的构造函数替换类声明。
示例:
@sealed
class Person {
msg: string;
constructor(message: string) {
this.msg = message;
}
show() {
return "Hello, " + this.msg;
}
}
在上面的示例中,当执行 @sealed 装饰器时,它将封闭构造函数和其原型,这样我们就无法继承 Person 类。
2. 方法装饰器
方法装饰器是在方法声明之前定义的。它应用于方法的属性描述符。它可以用于观察、修改或替换方法定义。我们不能在声明文件中使用方法装饰器。
方法装饰器函数的表达式接受三个参数。它们分别是:
- 类的构造函数(静态成员)或类的原型(实例成员)。
- 成员名称。
- 成员的属性描述符。
示例:
在下面的示例中, @log 装饰器将记录新的项目条目。
class Item {
itemArr: Array;
constructor() {
this.itemArr = [];
}
@log
Add(item: string): void {
this.itemArr.push(item);
}
GetAll(): Array {
return this.itemArr;
}
}
3. 存取器装饰器
存取器装饰器是在存取器声明之前定义的。它应用于存取器的属性描述符。它可以用于观察、修改或替换存取器的定义。
注意:存取器是类声明的getter和setter属性。
存取器装饰器函数的表达式接受三个参数。它们是:
- 静态成员的类的构造函数,或实例成员的类的原型。
- 成员名称。
- 成员的属性描述符。
示例:
在下面的示例中,一个存取器装饰器 (@configurable) 被应用于 Employee 类的一个成员。
class Employee {
private _salary: number;
private _name: string;
@configurable(false)
get salary() { return 'Rs. {this._salary}'; }
set salary(salary: any) { this._salary = +salary; }
@configurable(true)
get name() { return 'Sir/Madam,{this._name}'; }
set name(name: string) { this._name = name; }
}
4. 属性装饰器
属性装饰器是在属性声明之前定义的。它类似于方法装饰器。属性装饰器和方法装饰器之间唯一的区别是,它们不接受属性描述符作为参数,也不返回任何内容。
属性装饰器函数的表达式接受两个参数。它们是:
- 静态成员的类构造函数,或实例成员的类的原型。
- 成员名称。
示例:
在下面的示例中,@ReadOnly装饰器将使name属性变为只读,因此我们无法更改其值。
class Company {
@ReadOnly
name: string = "JavaTpoint.com";
}
let comp = new Company();
comp.name = 'SSSIT.com'; // Here, we can't change company name.
console.log(comp.name); // 'JavaTpoint.com'
5. 参数装饰器
参数装饰器是在参数声明之前定义的。它应用于类构造函数或方法声明的函数。它不能用在声明文件或任何其他环境上下文中(比如已声明的类)。
参数装饰器函数的表达式接受三个参数,它们分别是:
- 静态成员的类的构造函数或实例成员的类的原型。
- 成员名称。
- 参数在函数参数列表中的索引。
示例:
在下面的示例中,一个参数装饰器 (@required) 应用于 Person 类的成员参数。
class Person {
msg: string;
constructor(message: string) {
this.msg = message;
}
@validate
show(@required name: string) {
return "Hello " + name + ", " + this.msg;
}
}