[英]How to add and declare new property to class using decorator in typescript (angular)
[英]Add a decorator to a new property with a class decorator
我想知道的几乎所有内容都在标题中。 我想知道如何使用类装饰器添加带有其自身装饰器的新属性。
我想创建一个类装饰器Api(string []),它公开了类装饰器中列出的类方法。 为此,我想从Angular发出带有EventEmitter
的事件, EventEmitter
,我必须将@Output()
装饰器添加到新属性。
我可以吗?
下面举一个例子:我只有MyClass,其方法为process,open,close。 我想创建装饰器以公开我想要的任何方法(在此打开和关闭)。 我想象过一个添加了api
属性的类装饰器和一个方法装饰器来公开一个方法,也许吗?
class MyClass {
@Output() api = new EventEmitter();
$exposedMethods: object = {};
constructor() {
this.$exposedMethods = {
open: this.open.bind(this),
close: this.close.bind(this)
};
this.api.emit(this.$exposedMethods);
}
process() {
}
open() {
// stuff...
}
close() {
// stuff...
}
}
好吧,请做好准备,因为这是一个很难理解的概念 。
您可以在此处进行现场演示:
https://stackblitz.com/edit/angular-2kxtzs?file=src%2Fapp%2Fhello.component.ts
对于代码:
import { Component, Input, Output, EventEmitter } from '@angular/core';
const Expose: (methods: string[]) => ClassDecorator = (methods) => {
return component => {
for (const method of methods) {
const eventEmitterName = `${method}Emitter`;
component.prototype[eventEmitterName] = new EventEmitter();
const outputFactory = Output(method);
const orgFn = component.prototype[method];
component.prototype[method] = (...args) => {
orgFn(...args);
component.prototype[eventEmitterName].emit();
}
outputFactory(component.prototype, eventEmitterName);
}
}
}
@Component({
selector: 'hello',
template: `<button (click)="open()">Emit an open event</button>`,
styles: [`h1 { font-family: Lato; }`]
})
@Expose(['open'])
export class HelloComponent {
@Input() name: string;
open() {
console.log('Clicked on the button, now emitting an event');
}
ngOnInit() {}
}
类装饰器是函数。
在您的情况下,这是一个类装饰器工厂:您提供参数,并且它应该返回一个类装饰器。 这是您可以看到的签名:
const Expose: (methods: string[]) => ClassDecorator = (methods) => { ... }
它声明Expose
是一个返回Class Decorator的工厂。 您的工厂接受方法列表作为参数。
现在,该工厂需要返回一个类装饰器。 类装饰器是一个具有组件本身作为唯一参数的函数。 这是线
return component => { ... }
它返回一个符合ClassDecorator
签名的函数。
之后,您需要重写每个方法。 因此,您将通过一个简单的循环遍历它们。
在循环中,我们将创建一个新的事件发射器。 为简单起见,我们将使用名称[method]Emitter
。 因此,我们首先创建一个圣名:
const eventEmitterName = `${method}Emitter`;
完成此操作后,我们将其绑定到组件的原型:
component.prototype[eventEmitterName] = new EventEmitter();
现在,您有了事件发射器。
之后,您将需要将输出装饰器绑定到它。 如果遵循了第一步,您将了解Output
实际上也是一个工厂。 这意味着它将返回MethodDecorator
函数,其签名为
(component, methodKey) => { ... }
(有第三个参数称为描述符,但是您不需要它,因此我将忽略它)。
一旦知道了这一点,我们就会为我们的方法获取工厂结果:
const outputFactory = Output(method);
这将创建一个以您的方法命名的输出(此处为open
)。
完成此操作后,我们将覆盖给定的方法以在处理完成后发出事件。
这是基本的JS函数重写:
const orgFn = component.prototype[method];
component.prototype[method] = (...args) => {
orgFn(...args);
component.prototype[eventEmitterName].emit();
}
在最后一行,我们通过先前创建的事件发射器发射事件。
现在,我们要做的就是将此事件发射器绑定到我们的组件。 为此,我们只需调用输出工厂创建的方法装饰器即可。
outputFactory(component.prototype, eventEmitterName);
现在,您的装饰器已经完成并且可以工作。 正如您在stackblitz上看到的那样,正在运行open
函数中的代码,然后运行该代码,然后运行应用程序组件模板中(open)
输出的代码。
还有Voilààààà!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.