如何减少reducer中switch非空case数量解决SonarQube代码异味问题
解决方案
针对你遇到的SonarQube限制switch非空case数量的问题,有两种改动成本低、完全兼容原有逻辑的优化方案:
方案1:用对象映射表替换switch语句(改动最小,优先推荐)
你的所有case逻辑都是固定的action.type到处理函数的映射,直接用键值对对象存储映射关系即可,完全规避switch case数量限制,逻辑和原有代码100%等价,上线零风险。
实现代码:
// 定义Action处理函数的类型 type ActionHandler = (state: IEquipmentState, payload: any) => IEquipmentState // 构建Action类型到处理函数的映射表 const actionHandlers: Partial<Record<EquipmentActionTypes, ActionHandler>> = { [EquipmentActionTypes.REQUEST_EQUIPMENT]: (state) => reducerUtils.requestListData<IEquipmentState, IEquipment[]>(state, ['equipmentList']), [EquipmentActionTypes.RECEIVE_EQUIPMENT]: (state, payload) => reducerUtils.receiveListData<IEquipmentState, IEquipment[]>(state, ['equipmentList'], payload), [EquipmentActionTypes.ERROR_RECEIVE_EQUIPMENT]: (state, payload) => reducerUtils.errorListData<IEquipmentState, IEquipment[]>(state, ['equipmentList'], payload), [EquipmentActionTypes.REQUEST_EQUIPMENT_BY_ID]: (state) => reducerUtils.requestItemData<IEquipmentState, IEquipment>(state, ['selectedEquipment']), [EquipmentActionTypes.RECEIVE_EQUIPMENT_BY_ID]: (state, payload) => reducerUtils.receiveItemData<IEquipmentState, IEquipment>(state, ['selectedEquipment'], payload as IEquipment), [EquipmentActionTypes.ERROR_RECEIVE_EQUIPMENT_BY_ID]: (state, payload) => reducerUtils.errorItemData<IEquipmentState, IEquipment>(state, ['selectedEquipment'], payload), // 剩余所有Action的处理逻辑依次按上述格式添加即可 [EquipmentActionTypes.RESET_STATE]: (state) => resetSelectedEquipmentState(state) } export function equipmentReducer( lastState: IEquipmentState = new EquipmentState(), action: GenericAction<EquipmentActionTypes, any> ): IEquipmentState { // 匹配到对应处理函数则执行,否则返回原state,等价于原有switch的default逻辑 return actionHandlers[action.type]?.(lastState, action.payload) ?? lastState }
进阶优化:批量生成映射表
你的处理逻辑高度模式化,所有Action都遵循请求/接收/错误的三段式结构,仅参数不同,可以进一步封装批量生成逻辑,减少重复代码:
// 先定义所有业务实体的配置项 const entityConfigs = [ { prefix: 'EQUIPMENT', statePath: ['equipmentList'], isList: true, dataType: {} as IEquipment[] }, { prefix: 'EQUIPMENT_BY_ID', statePath: ['selectedEquipment'], isList: false, dataType: {} as IEquipment }, // 依次添加所有业务实体的配置:INITIAL_SPECIFICATION、MANUFACTURERS、SUPPLIERS等 ] // 批量生成handler entityConfigs.forEach(config => { const reqType = EquipmentActionTypes[`REQUEST_${config.prefix}` as keyof typeof EquipmentActionTypes] const resType = EquipmentActionTypes[`RECEIVE_${config.prefix}` as keyof typeof EquipmentActionTypes] const errType = EquipmentActionTypes[`ERROR_RECEIVE_${config.prefix}` as keyof typeof EquipmentActionTypes] actionHandlers[reqType] = (state) => config.isList ? reducerUtils.requestListData(state, config.statePath) : reducerUtils.requestItemData(state, config.statePath) actionHandlers[resType] = (state, payload) => config.isList ? reducerUtils.receiveListData(state, config.statePath, payload) : reducerUtils.receiveItemData(state, config.statePath, payload) actionHandlers[errType] = (state, payload) => config.isList ? reducerUtils.errorListData(state, config.statePath, payload) : reducerUtils.errorItemData(state, config.statePath, payload) })
后续新增业务Action只需要加一行配置即可,无需重复写处理逻辑。
方案2:按业务模块拆分reducer
你当前的reducer包含了设备、厂商、供应商、联系人多个独立业务逻辑,可以按业务拆分成多个子reducer,每个子reducer的case数量都远低于30,符合SonarQube规则的同时也提升了代码可维护性。
实现示例:
// 拆分设备核心业务reducer function equipmentCoreReducer(state: IEquipmentState, action: GenericAction<EquipmentActionTypes, any>): IEquipmentState { switch(action.type) { // 只处理设备本身的相关case,数量不超过30 case EquipmentActionTypes.REQUEST_EQUIPMENT: case EquipmentActionTypes.RECEIVE_EQUIPMENT: case EquipmentActionTypes.ERROR_RECEIVE_EQUIPMENT: // 其他设备核心相关case default: return state } } // 拆分厂商业务reducer function manufacturerReducer(state: IEquipmentState, action: GenericAction<EquipmentActionTypes, any>): IEquipmentState { switch(action.type) { // 只处理厂商相关的case case EquipmentActionTypes.REQUEST_MANUFACTURERS: case EquipmentActionTypes.RECEIVE_MANUFACTURERS: case EquipmentActionTypes.ERROR_RECEIVE_MANUFACTURERS: // 其他厂商相关case default: return state } } // 同理拆分供应商、联系人等业务的reducer // 组合子reducer export function equipmentReducer( lastState: IEquipmentState = new EquipmentState(), action: GenericAction<EquipmentActionTypes, any> ): IEquipmentState { let state = lastState state = equipmentCoreReducer(state, action) state = manufacturerReducer(state, action) state = supplierReducer(state, action) state = contactReducer(state, action) return state }
方案选择建议
- 仅需要快速修复SonarQube问题、不想改动现有逻辑:选方案1,1小时内即可完成改造
- 后续还会持续新增业务Action、希望优化代码可维护性:选方案2,长期收益更高
内容的提问来源于stack exchange,提问作者simpller
相关产品推荐
相关产品推荐

