执行顺序
- 属性装饰器
- 方法装饰器
- 方法参数装饰器
- 类装饰器
如果同一个类型的装饰器有多个,总是先执行后面的装饰器。
less
class NestedClass {
@IsString()
@exceedLength()
name: string;
constructor(props: any) {
this.name = props.name;
}
}
先执行exceedLength()再执行IsString()
类装饰器
可以为构造函数新增或修改变量或方法
typescript
@reportableClassDecorator
class BugReport {
constructor(t: string) {
this.title = t;
this._type = 'report';
}
}
// 类装饰器
function reportableClassDecorator<T extends { new (...args: any[]): {}}>(constructor: T) {
return class extends constructor {
reportingURL = "http://www...";
sayHello = () => {
console.log('hello everyone');
}
}
}
interface BugReportV2 extends BugReport {
reportingURL: string
sayHello: () => void
}
const report = new BugReport("shanghai") as BugReportV2;
console.log(report.name); // "http://www..."
report.sayHello(); // "hello everyone"
属性装饰器
可以用于收集属性信息,也可以用来给类添加额外的方法和属性
通过元数据修改
更便捷的获取格式化数据
typescript
import "reflect-metadata";
const formatMetadataKey = Symbol("format");
class BugReport {
_type: string;
title: string;
@format("My name is %s")
name: string = 'shenxin';
constructor(t: string) {
this.title = t;
this._type = 'report';
}
introduceMyself() {
const _tmpName = getFormat(this, 'name');
return _tmpName.replace("%s", this.name);
}
}
function format(formatString: string) {
return Reflect.metadata(formatMetadataKey, formatString);
}
function getFormat(target: any, propertyKey: string) {
return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}
interface BugReportV2 extends BugReport {
reportingURL: string
sayHello: () => void
}
const report = new BugReport("shanghai") as BugReportV2;
report.type = 'test';
report.name = "wangya";
console.log('name::: ', report.introduceMyself()); // "My name is wangya"
通过访问器修改
限制数据类型
typescript
class NestedClass {
@IsString()
name: string;
constructor(props: any) {
this.name = props.name;
}
}
function IsString() {
return function (target: any, key: string) {
let _key: string;
Object.defineProperty(target, key, {
get: () => _key,
set: value => {
if (typeof value !== 'string') {
throw(`${key} must be a string`)
}
_key = value;
}
});
}
}
const person = new NestedClass({
name: 28,
});
console.log('person: ', person.name); // [ERR]: "name must be a string"
方法装饰器
typescript
class BugReport {
_type: string;
title: string;
name: string = 'shenxin';
constructor(t: string) {
this.title = t;
this._type = 'report';
}
@addHello
getTitle() {
return this.title;
}
}
// 方法装饰器
function addHello(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const _getTitle = descriptor.value;
descriptor.value = function() {
return `hello ${_getTitle.bind(this)()}`;
}
}
const report = new BugReport("shanghai");
console.log(report.getTitle()); // "hello shanghai"
访问器装饰器
typescript
class BugReport {
_type: string;
title: string;
name: string = 'shenxin';
constructor(t: string) {
this.title = t;
this._type = 'report';
}
@addTmp
set type(value: string) {
this._type = value;
}
get type() {
return this._type;
}
}
// 访问器装饰器
function addTmp(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originSet = descriptor.set || function(){};
descriptor.set = function(value: string) {
// 获取方法参数
return originSet.call(this, `this is ${value}`);
}
}
const report = new BugReport("shanghai");
report.type = 'test';
console.log('report.type::: ', report.type); // "this is test"