如何使用泛型解决TypeScript的ts(2339)类型错误
问题分析
出现ts(2339)错误的核心原因是:你定义的INotificationData<NotificationPayload>没有在type属性和具体的payload类型之间建立明确的关联关系。当函数返回该类型的数组时,每个item的payload会被视为IEmailPayload | ISmsPayload的联合类型,TypeScript无法确定当前payload是否包含recipient属性(因为ISmsPayload没有该属性)。
解决方案
我们需要创建可区分联合类型,让每个type值与对应的payload类型严格绑定,具体步骤如下:
1. 定义类型映射表
先创建一个类型,将每种通知类型字符串映射到对应的payload接口:
type NotificationTypeMap = { EMAIL: IEmailPayload; SMS: ISmsPayload; PUSH_NOTIFICATION: {}; // 若有推送通知的payload类型,替换为实际接口即可 };
2. 生成关联的联合类型
通过映射类型生成一组绑定了type和对应payload的联合类型:
type NotificationData = { [Type in keyof NotificationTypeMap]: { type: Type; payload: NotificationTypeMap[Type]; }; }[keyof NotificationTypeMap];
这个NotificationData实际上是三个明确类型的联合:
{ type: 'EMAIL'; payload: IEmailPayload }{ type: 'SMS'; payload: ISmsPayload }{ type: 'PUSH_NOTIFICATION'; payload: 对应类型 }
3. 修改dispatcher函数的返回类型
将dispatcher的返回类型改为NotificationData[]:
const dispatcher = (): NotificationData[] => { return [ { type: "EMAIL", payload: generatePayloadEmail() }, { type: 'SMS', payload: generatePayloadSms() } ]; };
4. 通过类型窄化访问属性
现在你可以通过判断type属性来窄化payload的类型,TypeScript会正确推断出可用的属性:
const notifications = dispatcher(); if (notifications[0].type === 'EMAIL') { console.log(notifications[0].payload.recipient); // 无报错,TypeScript明确知道这是IEmailPayload } if (notifications[1].type === 'SMS') { console.log(notifications[1].payload.phoneNumber); // 正常访问phoneNumber属性 }
为什么这样有效?
可区分联合类型让TypeScript能够将type属性与对应的payload类型建立关联。当你判断type的值时,TypeScript会自动将payload的类型窄化为对应的接口,消除了联合类型的歧义。
内容的提问来源于stack exchange,提问作者Juan Andrade
相关产品推荐
相关产品推荐

