TypeScript type inference/narrowing challenge

后端 未结 1 914
盖世英雄少女心
盖世英雄少女心 2021-01-18 12:38

I\'m currently trying to improve the types on some existing code. My code looks roughly like this:

/* dispatcher.ts */
interface Message {
    messageType: s         


        
相关标签:
1条回答
  • 2021-01-18 12:58

    It's not possible, unless you are willing to change the code quite a bit.

    Your base interface

    interface Message {
        messageType: string;
    }
    

    is too general, I think messageType: string precludes any inference based on the value of the messageType, and looks like it's impossible to sufficiently narrow it in the Dispatcher interface.

    If you limit the code to AppMessage and its descendants only, here is an example how to make typescript to infer the types you need, guided by string literal types (keyof AppMessageMap is actually a union of string literal types "ADD_COMMENT" | "POST_PICTURE"):

    /* dispatcher.ts */
    
    class Dispatcher {    
        on<
            MessageType extends keyof AppMessageMap
        >(
            messageType: MessageType,
            handler: (message: AppMessageMap[MessageType] & {messageType: MessageType}) => void
        ): void { }
    }
    
    /* messages.ts */
    interface AddCommentMessage {
        commentId: number;
        comment: string;
        userId: number;
    }
    
    interface PostPictureMessage {
        pictureId: number;
        userId: number;
    }
    
    interface AppMessageMap {
        "ADD_COMMENT": AddCommentMessage,
        "POST_PICTURE": PostPictureMessage
    }
    type AppMessage = AppMessageMap[keyof AppMessageMap];
    
    /* app.ts */
    const dispatcher = new Dispatcher();
    
    
    dispatcher.on("ADD_COMMENT", (message) => {
        console.log(message.comment);
    });
    

    I also removed messageType property from the interfaces to avoid duplication, I think that intersection type in handler parameter achieves the same effect.

    0 讨论(0)
提交回复
热议问题