TypeScript泛型问题:判断泛型对象属性无法确定其类型
解决postMessage监听器的TypeScript类型推断问题
你的问题出在泛型的定义位置:把泛型<M extends keyof Messages>放在了监听函数上,导致TypeScript无法根据event.data.method的具体值来窄化event.data.data的类型——因为泛型M是整个函数的参数,不是针对每个消息类型的联合分支。
正确的做法是先定义所有合法消息的联合类型,再让监听器接收这个联合类型的MessageEvent,这样TypeScript就能通过method的判断自动完成类型窄化。
修改后的代码如下:
interface Messages { 'say-hi': { greeting: string; }; 'say-bye': { farewell: string; }; } // 生成所有合法消息数据的联合类型 type MessageEventData = { [M in keyof Messages]: { method: M; data: Messages[M]; }; }[keyof Messages]; // 监听器接收的是MessageEvent<MessageEventData> type MessageListener = ( e: MessageEvent<MessageEventData> ) => any; const addMessageEventListener = (listener: MessageListener): void => window.addEventListener('message', listener); addMessageEventListener(event => { if (event.data.method === 'say-hi') { // 现在可以正常访问greeting,类型推断生效了 console.log(event.data.data.greeting); } else if (event.data.method === 'say-bye') { console.log(event.data.data.farewell); } });
为什么原来的写法不行?
你原来的泛型写法会让event.data的类型变成{ method: M; data: Messages[M]; },但M是整个函数的泛型参数,TypeScript无法在函数内部根据method的具体值来锁定M的类型,所以event.data.data会被推断成Messages[keyof Messages](也就是两个类型的联合),自然无法直接访问greeting或farewell。
而用联合类型MessageEventData的话,每个分支都有明确的method和对应的data类型,TypeScript能识别出event.data.method === 'say-hi'是一个有效的类型守卫,自动把event.data.data窄化为Messages['say-hi']。
内容的提问来源于stack exchange,提问作者nikitakot
相关产品推荐
相关产品推荐

