TypeScript 类型推断/缩小挑战
Posted
技术标签:
【中文标题】TypeScript 类型推断/缩小挑战【英文标题】:TypeScript type inference/narrowing challenge 【发布时间】:2017-08-12 08:15:31 【问题描述】:我目前正在尝试改进一些现有代码的类型。我的代码大致是这样的:
/* 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
)。
如果现在无法做到这一点,请告诉我。我的印象是不是,但我不太确定。
【问题讨论】:
欢迎来到 Stack Overflow!请在问题本身的minimal reproducible example 中提供所有相关代码,而不仅仅是在第三方网站上。 【参考方案1】:这是不可能的,除非你愿意修改代码。
你的基本界面
interface Message
messageType: string;
太笼统了,我认为messageType: string
排除了基于messageType
的值的任何推断,并且看起来不可能在Dispatcher
接口中充分缩小它。
如果您将代码限制为仅AppMessage
及其后代,这里是一个示例,如何制作 typescript 以根据字符串文字类型推断您需要的类型(keyof AppMessageMap
实际上是字符串文字类型的联合 @ 987654327@):
/* 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
参数中的交集类型可以达到相同的效果。
【讨论】:
这是完美的答案,非常感谢。 TypeScript 类型系统的强大总是让我大吃一惊。我唯一改变的是使Dispatcher
通用,以便AppMessageMap
作为类型参数传递(我对同一代码库中的多个应用程序使用相同的Dispatcher
)。以上是关于TypeScript 类型推断/缩小挑战的主要内容,如果未能解决你的问题,请参考以下文章