import { AnyAction , Reducer } from 'redux' ; export type ObjectMapReducerType < S extends { } > = { [ key ] : S ; } ; interface ObjectMapReducerOptions { field ? : string ; deleteActionType ? : string ; reduceDeleteActionOnAll ? : boolean ; } param actionKey param subReducer param options param options . field param options . deleteActionType param options . reduceDeleteActionOnAll returns export const objectMapReducer = < S extends { } > ( actionKey , subReducer , options = { } ) : Reducer < ObjectMapReducerType < S > > => ( state = { } , action ) => { const key = action [ actionKey ] ; if ( key === undefined ) { return state ; } let { field = null , deleteActionType = null } = options ; const keyedState = field ? ( state [ field ] || { } ) : state ; let result = null ; if ( Array . isArray ( key ) ) { key . forEach ( ( singleKey ) => { result = updateSingleKey ( subReducer , deleteActionType , result , keyedState , singleKey , action ) ; } ) ; } else { result = updateSingleKey ( subReducer , deleteActionType , result , keyedState , key , action ) ; } if ( result && deleteActionType && action . type === deleteActionType && options . reduceDeleteActionOnAll ) { result = Object . keys ( result ) . reduce ( ( newState , key ) => { newState [ key ] = subReducer ( result [ key ] , action ) ; return newState ; } , { } ) ; } if ( ! result ) { return state ; } else if ( field ) { return { ... state , [ field ] : result } ; } else { return result ; } } ; const updateSingleKey = < S extends { } > ( subReducer , deleteActionType , result , state , key , action ) : S | null => { if ( deleteActionType && action . type === deleteActionType ) { if ( state [ key ] ) { if ( ! result ) { result = Object . assign ( { } , state ) ; } delete ( result [ key ] ) ; } } else { const nextState = subReducer ( state [ key ] , action ) ; if ( nextState !== state [ key ] ) { if ( ! result ) { result = Object . assign ( { } , state ) ; } if ( nextState === undefined ) { delete ( result [ key ] ) ; } else { result [ key ] = nextState ; } } } return result ; } ;