Я создаю сервер WebSocket в Typescript, в котором разные компоненты приложения должны иметь возможность регистрировать свои собственные обработчики запросов. Есть синглтон 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, так что любое руководство будет с благодарностью. Спасибо!