gpt4 book ai didi

typescript - 我可以在 Typescript 方法装饰器中访问目标类实例吗?

转载 作者:行者123 更新时间:2023-12-04 00:57:12 24 4
gpt4 key购买 nike

我正在 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 等于函数所在的 map (在 WebsocketHandler 内)。

然后我尝试使用这个工厂函数传入 target 作为处理程序的上下文:
function websocketRequest(requestName: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
WebsocketHandler.getInstance().registerRequestHandler(requestName, () => descriptor.value.call(target));
}
}

但后来我意识到 target 只是指 ListOfStuff 的原型(prototype),而不是实际的类实例。所以仍然没有帮助。

有什么办法可以在装饰工厂中获取 ListOfStuff 的实例(这样我就可以访问 this.list )?我是否应该以其他方式构造我的装饰器,以便它与类的实例而不是它的原型(prototype)相关联?这是一个演示问题 https://repl.it/@Chap/WonderfulLuckyDatalogs 的 Repl

这是我第一次搞砸装饰器,而且我对 Typescript 也很陌生,所以任何指导都将不胜感激。谢谢!

最佳答案

无法访问 Typescript 方法装饰器中的实例。但是可以使用装饰器更改原型(prototype)和构造函数。所以可能的解决方案是使用两个装饰器:第一个“标记”方法,第二个更改构造函数添加注册逻辑。

下面我将尝试说明这个想法

const SubMethods = Symbol('SubMethods'); // just to be sure there won't be collisions

function WebsocketRequest(requestName: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
target[SubMethods] = target[SubMethods] || new Map();
// Here we just add some information that class decorator will use
target[SubMethods].set(propertyKey, requestName);
};
}

function WebSocketListener<T extends { new(...args: any[]): {} }>(Base: T) {
return class extends Base {
constructor(...args: any[]) {
super(...args);
const subMethods = Base.prototype[SubMethods];
if (subMethods) {
subMethods.forEach((requestName: string, method: string) => {
WebsocketHandler.getInstance()
.registerRequestHandler(
requestName,
() => (this as any)[method]()
);
});
}
}
};
}

用法:
@WebsocketListener
class ListOfStuff {
private list = [];

@WebsocketRequest("getListLength")
private listLengthRequest() : WebSocketResponse {
return new WebSocketResponse(this.list.length);
}
}

Updated repl

关于typescript - 我可以在 Typescript 方法装饰器中访问目标类实例吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61439271/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com