TypeScript 装饰器
字数:1215,预计阅读时间:6min
装饰器(Decorators)可用来装饰类,属性,及方法,甚至是函数的参数,以改变和控制这些对象的表现,获得一些功能。 装饰器以 以下两种风格均是合法的: @f @g x @f
@g
x ES 中装饰器处于 Stage 2 阶段 ,TypeScript 中通过开启相应编译开关来使用。 {
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
} 一个简单的示例一个简单的示例,展示了 TypeScript 中如何编写和使用装饰器。 function log(
_target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
descriptor.value = function() {
console.log(`method ${propertyKey} called`);
return originalMethod.apply(this, arguments);
};
}
上面的示例中,创建了名为 执行结果: method sayHello called
hello 装饰器的工厂方法上面的装饰器比较呆板,设想我们想将它变得更加灵活和易于复用一些,则可以通过创建一个工厂方法来实现。因为本质上装饰器就是个普通函数,函数可通过另外的函数来创建和返回,同时装饰器的使用本质上也是一个函数调用。通过传递给工厂方法不同的参数,以获得不同表现的装饰器。 function logFactory(prefix: string) {
return function log(
_target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
descriptor.value = function() {
console.log(`method ${propertyKey} called`);
return originalMethod.apply(this, arguments);
};
};
}
执行结果: [debug] method sayHello called
hello
[info] method sum called 多个装饰器多个装饰器可同时作用于同一对象,按顺序书写出需要运用的装饰器即可。其求值(evaluate)和真正被执行(call)的顺序是反向的。即,排在前面的先求值,排在最后的先执行。 譬如, function f() {
console.log("f(): evaluated");
return function(target, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("f(): called");
};
}
求值 的过程就体现在装饰器可能并不直接是一个可调用的函数,而是一个工厂方法或其他表达式,只有在这个工厂方法或表达式被求值后,才得到真正被调用的装饰器。 所以在这个示例中,先依次对 运行结果: f(): evaluated
g(): evaluated
g(): called
f(): called 不同类型的装饰器类的装饰器作用于类(Class)上的装饰器,用于修改类的一些属性。如果装饰器有返回值,该返回值将替换掉该类的声明而作为新的构造器使用。 装饰器入参:
示例: function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
另一个示例: function classDecorator<T extends { new (...args: any[]): {} }>(
constructor: T
) {
return class extends constructor {
newProperty = "new property";
hello = "override";
};
}
因为 方法的装饰器装饰器作用于类的方法时可用于观察,修改或替换该方法。如果装饰器有返回值,将替换掉被作用方法的属性描述器(roperty Descriptor)。 装饰器入参依次为:
示例: function enumerable(value: boolean) {
return function(
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
descriptor.enumerable = value;
};
}
上面示例中 类的方法可以是设置器(setter)或获取器(getter)。当两者成对出现时,应当只对其中一个运用装饰器,谁先出现就用在谁身上。因为装饰器应用时是用在 class Test {
private _foo = 1;
@logFactory("[info]")
get foo() {
return this._foo;
}
//🚨 Decorators cannot be applied to multiple get/set accessors of the same name.ts(1207)
@logFactory("[info]")
set foo(val: number) {
this._foo = val;
}
} 属性的装饰器作用于类的属性时,其入参依次为:
此时并没有提供第三个入参,即该属性的属性描述器。因为定义属性时,没有相应机制来描述该属性,同时属性初始化时也没有方式可以对其进行修改或观察。 如果装饰器有返回值,将被忽略。 因此,属性装饰器仅可用于观察某个属性是否被创建。 一个示例:
这个示例中,通过将原属性删除,创建带设置器和获取器的同名属性,来达到对属性值变化的监听。注意此时操作的已经不是最初那个属性了。 运行结果: Set: name => remo
Set: name => Remo
Get: name => Remo 参数的装饰器装饰器也可作用于方法的入参,这个方法不仅限于类的成员方法,还可以是类的构造器。装饰器的返回值会被忽略。 当作用于方法的参数时,装饰器的入参依次为:
比如,定义一个参数为必传的: import "reflect-metadata";
上面示例中, 相关资源 |

【推荐】FlashTable:表单开发界的极速跑车,让你的开发效率一路狂飙
【推荐】Flutter适配HarmonyOS 5知识地图,实战解析+高频避坑指南
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步