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; } };
核心逻辑说明
Exclude工具类型:Exclude<DatePickerActionType, DatePickerActionType.PICK_DATE>会把枚举里的PICK_DATE剔除,得到剩下的PICK_YEAR/PICK_MONTH/PICK_HOURS/PICK_MINUTES的联合类型。- 映射类型生成统一Action:
{ [K in NonDateActionTypes]: { type: K; payload: number } }会遍历所有非PICK_DATE的枚举成员,为每个成员生成对应的Action类型(type是当前枚举值,payload固定为number)。 - 转成联合类型:最后通过
[NonDateActionTypes]索引访问,把映射出来的对象类型转换成联合类型,再和PICK_DATE的特殊Action合并,就得到了完整的Action类型。
这种写法的优势很明显:后续如果枚举新增其他需要number类型payload的成员,完全不用修改Action类型定义,TypeScript会自动把新成员纳入进去。
内容的提问来源于stack exchange,提问作者Andyally
相关产品推荐
相关产品推荐

