import { Reducer } from 'redux'; import { ActionTypes, TodoAction, TodoActionLookup } from '../actions'; import { Draft, produce } from 'immer'; export type ImmerReducer = (state: Draft, action: A) => T; export type HandlerMap = { [actionType in ActionTypes]?: ImmerReducer }; function isHandlerFunction(handlerOrMap: HandlerMap | ImmerReducer): handlerOrMap is ImmerReducer { if (typeof handlerOrMap === 'function') { return true; } return false; } export function createReducer( initialState: T, handlerOrMap: HandlerMap | ImmerReducer ): Reducer { return function reducer(state = initialState, action: TodoAction | TodoActionLookup[AType]): T { if (isHandlerFunction(handlerOrMap)) { return produce(state, draft => handlerOrMap(draft, action as TodoActionLookup[AType])); } else if (handlerOrMap.hasOwnProperty(action.type)) { const handler = handlerOrMap[action.type] as ImmerReducer; return produce(state, draft => handler(draft, action)); } else { return state; } }; }