TypeScript类型推断/缩小挑战 [英] TypeScript type inference/narrowing challenge

查看:105
本文介绍了TypeScript类型推断/缩小挑战的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试改进某些现有代码的类型.我的代码大致如下:

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

/* dispatcher.ts */
interface Message {
    messageType: string;
}

class Dispatcher<M extends Message> {    
    on<
        MessageType extends M["messageType"],
        SubMessage extends M & { messageType: MessageType }
    >(
        messageType: MessageType,
        handler: (message: SubMessage) => void
    ): void { }
}

/* messages.ts */
interface AddCommentMessage {
    messageType: "ADD_COMMENT";
    commentId: number;
    comment: string;
    userId: number;
}

interface PostPictureMessage {
    messageType: "POST_PICTURE";
    pictureId: number;
    userId: number;
}

type AppMessage = AddCommentMessage | PostPictureMessage;

/* app.ts */
const dispatcher = new Dispatcher<AppMessage>();

dispatcher.on("ADD_COMMENT", (message: AddCommentMessage ) => {
                                    /* ^^ REMOVE THIS TYPE HINT!*/
    console.log(message.comment);
});

我想消除显式缩小传递给消息处理程序的消息类型(在其中/*REMOVE THIS TYPE HINT!*/所在)的需要,这样它就可以正确地缩小为具有匹配的messageType类型的类型(例如如果messageType"ADD_COMMENT",则message应该是AddCommentMessage).

I'd like to remove the need to explicitly narrow the type of the message passed to the message handler (where /*REMOVE THIS TYPE HINT!*/ is), such that it correctly narrows to the type that has a matching messageType type (e.g. if messageType is "ADD_COMMENT" then message should be AddCommentMessage).

如果现在无法实现,请告诉我.我觉得不是,但是我不太确定.

If this is not possible right now please let me know. I'm under the impression that it isn't but I'm not quite sure.

推荐答案

这是不可能的,除非您愿意对代码进行一些更改.

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

您的基本界面

interface Message {
    messageType: string;
}

太笼统了,我认为messageType: string排除了基于messageType值的任何推断,并且看起来不可能在Dispatcher界面中充分缩小它的范围.

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.

如果仅将代码限制为AppMessage及其子代,下面是一个示例,该示例如何在字符串文字类型的指导下使typescript推断所需的类型(keyof AppMessageMap实际上是字符串文字类型的并集"ADD_COMMENT" | "POST_PICTURE"):

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);
});

我还从接口中删除了messageType属性,以避免重复,我认为handler参数中的交集类型可以达到相同的效果.

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

这篇关于TypeScript类型推断/缩小挑战的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆