You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用泛型解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 19:06:28