diff --git a/src/utils/composeReducers.js b/src/utils/composeReducers.js index 4d654ecfbe..e1f4249933 100644 --- a/src/utils/composeReducers.js +++ b/src/utils/composeReducers.js @@ -1,12 +1,18 @@ import mapValues from '../utils/mapValues'; import pick from '../utils/pick'; +import invariant from 'invariant'; export default function composeReducers(reducers) { const finalReducers = pick(reducers, (val) => typeof val === 'function'); return function composition(state = {}, action) { - return mapValues(finalReducers, (store, key) => - store(state[key], action) - ); + return mapValues(finalReducers, (reducer, key) => { + const newState = reducer(state[key], action); + invariant( + typeof newState !== 'undefined', + `Reducer ${key} returns undefined. By default reducer should return original state.` + ); + return newState; + }); }; } diff --git a/test/composeReducers.spec.js b/test/composeReducers.spec.js index c0ce3c919e..0e578df68e 100644 --- a/test/composeReducers.spec.js +++ b/test/composeReducers.spec.js @@ -29,5 +29,30 @@ describe('Utils', () => { Object.keys(reducer({}, { type: 'push' })) ).toEqual(['stack']); }); + + it('should throw an error if undefined return from reducer', () => { + const reducer = composeReducers({ + stack: (state = []) => state, + bad: (state = [], action) => { + if (action.type === 'something') { + return state; + } + } + }); + expect(() => reducer({}, {type: '@@testType'})).toThrow(); + }); + + it('should throw an error if undefined return not by default', () => { + const reducer = composeReducers({ + stack: (state = []) => state, + bad: (state = 1, action) => { + if (action.type !== 'something') { + return state; + } + } + }); + expect(reducer({}, {type: '@@testType'})).toEqual({stack: [], bad: 1}); + expect(() => reducer({}, {type: 'something'})).toThrow(); + }); }); });