【发布时间】:2020-08-09 20:24:50
【问题描述】:
我正在 Typescript 中创建一个 WebSocket 服务器,其中不同的应用程序组件应该能够注册自己的请求处理程序。有一个单例 WebsocketHandler 提供了这种行为。
没有装饰器,一个类可以像这样注册它的请求处理程序:
class ListOfStuff {
private list = [];
constructor() {
//Register listLengthRequest as a request handler
WebsocketHandler.getInstance().registerRequestHandler('getListLength', () => this.listLengthRequest());
}
private listLengthRequest() : WebSocketResponse {
return new WebSocketResponse(this.list.length);
}
}
class WebsocketHandler {
private constructor() {}
private static instance = new WebsocketHandler();
static getInstance() {
return this.instance;
}
registerRequestHandler(requestName: string, handler: () => WebSocketResponse) {
//Store this handler in a map for when a request is received later
}
}
class WebSocketResponse {
constructor(content: any) {}
}
效果很好。但是,我试图用方法装饰器替换构造函数中的注册调用。理想情况下,ListOfStuff 应如下所示:
class ListOfStuff {
private list = [];
@websocketRequest("getListLength")
private listLengthRequest() : WebSocketResponse {
return new WebSocketResponse(this.list.length);
}
}
但是,在为@websocketRequest 创建了一个装饰器工厂之后,我无法弄清楚如何让listLengthRequest() 在正确的上下文中执行。我试过这个工厂函数:
function websocketRequest(requestName: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
WebsocketHandler.getInstance().registerRequestHandler(requestName, descriptor.value);
}
}
这使得this 等于函数所在的映射(在WebsocketHandler 内部)。
然后我尝试使用这个工厂函数将target 作为处理程序的上下文传递:
function websocketRequest(requestName: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
WebsocketHandler.getInstance().registerRequestHandler(requestName, () => descriptor.value.call(target));
}
}
但后来我意识到target 仅指ListOfStuff 的原型,而不是实际的类实例。所以仍然没有帮助。
有什么方法可以在装饰器工厂中获取ListOfStuff 的实例(这样我就可以访问this.list)了吗?我应该以其他方式构造我的装饰器,以便它与类的实例而不是它的原型相关联吗?这是一个演示问题的 Repl https://repl.it/@Chap/WonderfulLuckyDatalogs
这是我第一次搞砸装饰器,而且我对 Typescript 也很陌生,所以任何指导都将不胜感激。谢谢!
【问题讨论】:
-
我是否正确理解目标是在
WebsocketHandler发生某些事情时调用每个ListOfStuff实例的listLengthRequest? -
是的。
WebsocketHandler内部的逻辑会在两个方法注册同一个requestName时产生警告,因此这实际上仅适用于创建一次的类。但是还有其他WebsocketHandler回调我打算使用应该在每个实例上触发的装饰器来公开。
标签: typescript decorator