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

React中结合Enum与不同Payload类型的useReducer类型定义

解决方案

当然有办法不用逐个写,借助TypeScript的Exclude工具类型和映射类型就能实现:

完整实现代码

enum DatePickerActionType {
    PICK_YEAR = 'PICK_YEAR',
    PICK_MONTH = 'PICK_MONTH',
    PICK_DATE = 'PICK_DATE',
    PICK_HOURS = 'PICK_HOURS',
    PICK_MINUTES = 'PICK_MINUTES',
}

// 先定义排除PICK_DATE后的枚举成员类型
type NonDateActionTypes = Exclude<DatePickerActionType, DatePickerActionType.PICK_DATE>;

// 构建最终的Action联合类型
type DatePickerAction =
  | { type: DatePickerActionType.PICK_DATE; payload: Date }
  | { [K in NonDateActionTypes]: { type: K; payload: number } }[NonDateActionTypes];

// 测试Reducer的类型推断
const datePickerReducer = (state: DatePickerValue, action: DatePickerAction): DatePickerValue => {
    switch (action.type) {
        case DatePickerActionType.PICK_DATE: {
            const a = action.payload; // 现在正确推断为Date类型
            return state;
        }
        case DatePickerActionType.PICK_YEAR: {
            const b = action.payload; // 正确推断为number类型
            return state;
        }
        // 其他case的payload都会自动推断为number
        default:
            return state;
    }
};

核心逻辑说明

  1. Exclude工具类型:Exclude<DatePickerActionType, DatePickerActionType.PICK_DATE>会把枚举里的PICK_DATE剔除,得到剩下的PICK_YEAR/PICK_MONTH/PICK_HOURS/PICK_MINUTES的联合类型。
  2. 映射类型生成统一Action:{ [K in NonDateActionTypes]: { type: K; payload: number } }会遍历所有非PICK_DATE的枚举成员,为每个成员生成对应的Action类型(type是当前枚举值,payload固定为number)。
  3. 转成联合类型:最后通过[NonDateActionTypes]索引访问,把映射出来的对象类型转换成联合类型,再和PICK_DATE的特殊Action合并,就得到了完整的Action类型。

这种写法的优势很明显:后续如果枚举新增其他需要number类型payload的成员,完全不用修改Action类型定义,TypeScript会自动把新成员纳入进去。


内容的提问来源于stack exchange,提问作者Andyally

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:52:16