Discriminated unions类型匹配问题:函数参数与payload类型不兼容
问题原因
TypeScript 编译器无法在泛型函数的条件分支中自动关联message的具体类型与onMessage的参数类型。因为TMessageType是泛型参数,属于未被具体化的类型——编译器没办法在if(message.type === messageType)这个判断里,确认当前message的payload正好匹配onMessage期望的TPayload类型,即便逻辑上完全成立。
解决办法
方案1:类型断言(快速解决)
直接通过类型断言告诉编译器当前message的具体类型,因为已经做了type匹配判断,这个断言是安全的:
const someFn = <TMessageType extends Message['type']>( messageType: TMessageType, onMessage: ( payload?: Extract<Message, { type: TMessageType }> extends { payload: infer TPayload; } ? TPayload : undefined ) => void ) => { const handleMessage = (message: Message) => { if(message.type === messageType) { // 添加类型断言 onMessage((message as Extract<Message, { type: TMessageType }>).payload); } } };
方案2:重构为映射类型(更易维护)
当消息类型数量较多时,用映射类型统一管理消息类型与payload的对应关系,能让类型推导更清晰,减少重复代码:
// 定义消息类型与payload的映射 type MessagePayloadMap = { selectCase: undefined; updateNotification: { title: string; message: string }; // 其他20+种消息类型都在这里添加 }; // 自动生成Message联合类型 type Message = { [K in keyof MessagePayloadMap]: { type: K; payload?: MessagePayloadMap[K]; }; }[keyof MessagePayloadMap]; const someFn = <TMessageType extends keyof MessagePayloadMap>( messageType: TMessageType, onMessage: (payload?: MessagePayloadMap[TMessageType]) => void ) => { const handleMessage = (message: Message) => { if (message.type === messageType) { onMessage(message.payload as MessagePayloadMap[TMessageType]); } }; };
方案3:泛型类型谓词
如果想用类型谓词,需要定义泛型版本的类型判断函数,让编译器能正确窄化message的类型:
// 泛型类型谓词函数 function isTargetMessage<T extends Message['type']>( message: Message, targetType: T ): message is Extract<Message, { type: T }> { return message.type === targetType; } const someFn = <TMessageType extends Message['type']>( messageType: TMessageType, onMessage: ( payload?: Extract<Message, { type: TMessageType }> extends { payload: infer TPayload; } ? TPayload : undefined ) => void ) => { const handleMessage = (message: Message) => { if (isTargetMessage(message, messageType)) { // 此时message类型已被正确窄化,payload类型匹配 onMessage(message.payload); } } };
内容的提问来源于stack exchange,提问作者f0nt41n3
相关产品推荐
相关产品推荐

