【问题标题】:Typing a generic websocket handler键入通用 websocket 处理程序
【发布时间】:2021-09-08 13:46:23
【问题描述】:

我正在尝试找到处理键入通用 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 类中的 message.type

有没有办法让它工作,还是我在每个处理程序中都坚持讨厌的类型转换/断言?

【问题讨论】:

    标签: reactjs typescript websocket typescript-generics


    【解决方案1】:

    我看不到 PlannerTypes.SearchResults 是什么,所以我不确定你为什么需要这样做 (data as unknown) as PlannerTypes.SearchResults。如果PlannerTypes.SearchResultsWSMessage 的子类型(应该如此),您应该可以只使用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 代码不应该知道处理程序类型采用什么,但我想这在方案中并不是什么大问题。
    猜你喜欢
    • 2016-04-10
    • 2015-02-27
    • 2022-10-07
    • 2021-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多