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

TypeScript中基于枚举的映射类型如何省略无负载事件定义

解决TypeScript映射类型索引不匹配问题

问题核心

当Payload类型仅包含有payload的事件枚举键时,直接用所有Event枚举值去索引Payload会触发Type 'T' cannot be used to index type 'Payload'错误——因为部分枚举值不在Payload的键集合中。

解决方案

方案1:条件类型+交叉类型

通过条件类型判断当前事件枚举是否存在于Payload的键中,动态生成对应结构:

enum Event {
  Click,
  Hover,
  Submit,
}

// 仅定义有payload的事件
type Payload = {
  [Event.Submit]: { formData: FormData };
};

// 映射类型:有payload的事件强制携带对应结构,无payload的事件无需payload字段
type EventWithOptionalPayload<T extends Event> = {
  type: T;
} & (T extends keyof Payload ? { payload: Payload[T] } : { payload?: never });

// 合法用法
const clickEvent: EventWithOptionalPayload<Event.Click> = { type: Event.Click };
const submitEvent: EventWithOptionalPayload<Event.Submit> = { 
  type: Event.Submit, 
  payload: { formData: new FormData() } 
};

这里payload?: never确保无payload的事件可以完全省略该字段,同时类型检查会阻止错误传入payload。

方案2:拆分事件子集+类型合并

先将Event拆分为有payload和无payload的两个子集,分别定义类型后合并:

enum Event {
  Click,
  Hover,
  Submit,
}

type Payload = {
  [Event.Submit]: { formData: FormData };
};

// 拆分事件类型
type EventsWithPayload = keyof Payload;
type EventsWithoutPayload = Exclude<Event, EventsWithPayload>;

// 分别定义两类事件结构
type EventWithPayload<T extends EventsWithPayload> = {
  type: T;
  payload: Payload[T];
};

type EventWithoutPayload<T extends EventsWithoutPayload> = {
  type: T;
};

// 合并为最终映射类型
type EventWithOptionalPayload<T extends Event> = 
  T extends EventsWithPayload ? EventWithPayload<T> : EventWithoutPayload<T>;

// 合法用法
const hoverEvent: EventWithOptionalPayload<Event.Hover> = { type: Event.Hover };
const submitEvent: EventWithOptionalPayload<Event.Submit> = { 
  type: Event.Submit, 
  payload: { formData: new FormData() } 
};

这种方式结构更清晰,无payload的事件类型中完全不存在payload属性,严格符合“省略无payload事件的undefined声明”的需求。

内容的提问来源于stack exchange,提问作者Joel'-'

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 05:25:03