import {Action, Hash, Reducer} from "../interfaces"; // helper function function pickReducers(reducers:Hash):Hash { var initialResult:Hash = {}; return Object .keys(reducers) .reduce((finalReducer:Hash, key:string):Hash => { if (typeof reducers[key] === 'function') { finalReducer[key] = reducers[key]; } return finalReducer; }, initialResult); } // mixed reducer type is not supported, but I want to add them later on. export function combineReducers(reducers:Hash):Reducer { const finalReducers:Hash = pickReducers(reducers); const keys = Object.keys(finalReducers); var combinedReducer = >(state:TState, action:Action) => { if (typeof state === "undefined") state = {}; var hasChanged:boolean = false; var finalState:TState = keys.reduce((_state:TState, key:string):TState => { var nextState:TState; var previousStateForKey:any = _state[key]; var nextStateForKey:any = finalReducers[key]( _state[key], action ); hasChanged = hasChanged || previousStateForKey !== nextStateForKey; if (!hasChanged) { return _state; } else { nextState = Object.assign({}, _state); nextState[key] = nextStateForKey; return nextState; } }, state); return hasChanged ? finalState : state; }; return combinedReducer as Reducer; } export function passOrCombineReducers(reducers:Reducer|Hash):Reducer { if (typeof reducers !== 'function') { return combineReducers(reducers as Hash); } else { return reducers as Reducer; } }