键入一个通用的 websocket 处理程序
Typing a generic websocket handler
我正在尝试找到处理键入通用 websocket 处理程序的最佳方法。现有处理程序的实现如下所示:
type WSMessage = {
type: string;
[key: string]: unknown;
}
type HandlerFunc = (data: WSMessage) => void;
class PersistentWebsocket {
subscriptions = {};
initializeWebsocket(): void {
this.socket.onmessage = (event) => {
this.processMessage(JSON.parse(event.data) as WSMessage);
};
}
processMessage(message: WSMessage): void {
for(const handler of this.subscriptions[message.type] || []) {
handler(message);
}
}
}
然后我有一个使用这个 websocket 的钩子:
export function useWebsocketSubscription(
websocket: PersistentWebsocket,
type: string,
handler: HandlerFunc,
): void {
useEffect(() => {
websocket.subscribe(type, handler);
return () => {
websocket.unsubscribe(type, handler);
};
});
}
这样调用:
useWebsocketSubscription(websocket, "use-search-results", (data) => {
const d = (data as unknown) as PlannerTypes.SearchResults;
setActivityOptions(d.results.activities);
setLocationOptions(d.results.locations);
setMode(DisplayMode.search);
});
我真的很想能够删除 data as unknown as ActualType
声明,但我不知道如何编写泛型,让我定义在 websocket 消息的接口中传递的处理函数会符合。一切都在抱怨,因为 WSMessage 可能没有更具体的消息所期望的键,或者导致语法错误,或者打字稿不喜欢我在 PersistentWebsocket
class.[=16 中访问 message.type
=]
有没有办法让它工作,或者我是否在每个处理程序中都遇到了令人讨厌的 typecast/assertion?
我看不到什么 PlannerTypes.SearchResults
,所以我不确定您为什么需要这样做 (data as unknown) as PlannerTypes.SearchResults
。如果 PlannerTypes.SearchResults
是 WSMessage
的子类型(它应该是),你应该能够做到 data as PlannerTypes.SearchResults
.
如果你想在每次有钩子时都避免强制转换,你可以为每个 websocket 类型写 overloaded declarations:
export function useWebsocketSubscription(
websocket: PersistentWebsocket,
type: "use-search-results",
handler: (data: PlannerTypes.SearchResults) => void
): void;
export function useWebsocketSubscription(
websocket: PersistentWebsocket,
type: string,
handler: HandlerFunc
): void {
... definition ...
}
我正在尝试找到处理键入通用 websocket 处理程序的最佳方法。现有处理程序的实现如下所示:
type WSMessage = {
type: string;
[key: string]: unknown;
}
type HandlerFunc = (data: WSMessage) => void;
class PersistentWebsocket {
subscriptions = {};
initializeWebsocket(): void {
this.socket.onmessage = (event) => {
this.processMessage(JSON.parse(event.data) as WSMessage);
};
}
processMessage(message: WSMessage): void {
for(const handler of this.subscriptions[message.type] || []) {
handler(message);
}
}
}
然后我有一个使用这个 websocket 的钩子:
export function useWebsocketSubscription(
websocket: PersistentWebsocket,
type: string,
handler: HandlerFunc,
): void {
useEffect(() => {
websocket.subscribe(type, handler);
return () => {
websocket.unsubscribe(type, handler);
};
});
}
这样调用:
useWebsocketSubscription(websocket, "use-search-results", (data) => {
const d = (data as unknown) as PlannerTypes.SearchResults;
setActivityOptions(d.results.activities);
setLocationOptions(d.results.locations);
setMode(DisplayMode.search);
});
我真的很想能够删除 data as unknown as ActualType
声明,但我不知道如何编写泛型,让我定义在 websocket 消息的接口中传递的处理函数会符合。一切都在抱怨,因为 WSMessage 可能没有更具体的消息所期望的键,或者导致语法错误,或者打字稿不喜欢我在 PersistentWebsocket
class.[=16 中访问 message.type
=]
有没有办法让它工作,或者我是否在每个处理程序中都遇到了令人讨厌的 typecast/assertion?
我看不到什么 PlannerTypes.SearchResults
,所以我不确定您为什么需要这样做 (data as unknown) as PlannerTypes.SearchResults
。如果 PlannerTypes.SearchResults
是 WSMessage
的子类型(它应该是),你应该能够做到 data as PlannerTypes.SearchResults
.
如果你想在每次有钩子时都避免强制转换,你可以为每个 websocket 类型写 overloaded declarations:
export function useWebsocketSubscription(
websocket: PersistentWebsocket,
type: "use-search-results",
handler: (data: PlannerTypes.SearchResults) => void
): void;
export function useWebsocketSubscription(
websocket: PersistentWebsocket,
type: string,
handler: HandlerFunc
): void {
... definition ...
}