22import {
33 createStore ,
44 combineReducers ,
5- __DO_NOT_USE__ActionTypes as ActionTypes
6- } from '../'
5+ Reducer ,
6+ AnyAction ,
7+ __DO_NOT_USE__ActionTypes as ActionTypes ,
8+ CombinedState
9+ } from '..'
710
811describe ( 'Utils' , ( ) => {
912 describe ( 'combineReducers' , ( ) => {
1013 it ( 'returns a composite reducer that maps the state keys to given reducers' , ( ) => {
1114 const reducer = combineReducers ( {
12- counter : ( state = 0 , action ) =>
15+ counter : ( state : number = 0 , action ) =>
1316 action . type === 'increment' ? state + 1 : state ,
14- stack : ( state = [ ] , action ) =>
17+ stack : ( state : any [ ] = [ ] , action ) =>
1518 action . type === 'push' ? [ ...state , action . value ] : state
1619 } )
1720
18- const s1 = reducer ( { } , { type : 'increment' } )
21+ const s1 = reducer ( undefined , { type : 'increment' } )
1922 expect ( s1 ) . toEqual ( { counter : 1 , stack : [ ] } )
2023 const s2 = reducer ( s1 , { type : 'push' , value : 'a' } )
2124 expect ( s2 ) . toEqual ( { counter : 1 , stack : [ 'a' ] } )
2225 } )
2326
2427 it ( 'ignores all props which are not a function' , ( ) => {
28+ // we double-cast because these conditions can only happen in a javascript setting
2529 const reducer = combineReducers ( {
26- fake : true ,
27- broken : 'string' ,
28- another : { nested : 'object' } ,
30+ fake : ( true as unknown ) as Reducer ,
31+ broken : ( 'string' as unknown ) as Reducer ,
32+ another : ( { nested : 'object' } as unknown ) as Reducer ,
2933 stack : ( state = [ ] ) => state
3034 } )
3135
32- expect ( Object . keys ( reducer ( { } , { type : 'push' } ) ) ) . toEqual ( [ 'stack' ] )
36+ expect ( Object . keys ( reducer ( undefined , { type : 'push' } ) ) ) . toEqual ( [
37+ 'stack'
38+ ] )
3339 } )
3440
3541 it ( 'warns if a reducer prop is undefined' , ( ) => {
@@ -55,7 +61,7 @@ describe('Utils', () => {
5561
5662 it ( 'throws an error if a reducer returns undefined handling an action' , ( ) => {
5763 const reducer = combineReducers ( {
58- counter ( state = 0 , action ) {
64+ counter ( state : number = 0 , action ) {
5965 switch ( action && action . type ) {
6066 case 'increment' :
6167 return state + 1
@@ -77,12 +83,14 @@ describe('Utils', () => {
7783 expect ( ( ) => reducer ( { counter : 0 } , null ) ) . toThrow (
7884 / " c o u n t e r " .* a n a c t i o n /
7985 )
80- expect ( ( ) => reducer ( { counter : 0 } , { } ) ) . toThrow ( / " c o u n t e r " .* a n a c t i o n / )
86+ expect ( ( ) =>
87+ reducer ( { counter : 0 } , ( { } as unknown ) as AnyAction )
88+ ) . toThrow ( / " c o u n t e r " .* a n a c t i o n / )
8189 } )
8290
8391 it ( 'throws an error on first call if a reducer returns undefined initializing' , ( ) => {
8492 const reducer = combineReducers ( {
85- counter ( state , action ) {
93+ counter ( state : number , action ) {
8694 switch ( action . type ) {
8795 case 'increment' :
8896 return state + 1
@@ -93,7 +101,9 @@ describe('Utils', () => {
93101 }
94102 }
95103 } )
96- expect ( ( ) => reducer ( { } ) ) . toThrow ( / " c o u n t e r " .* i n i t i a l i z a t i o n / )
104+ expect ( ( ) => reducer ( undefined , { type : '' } ) ) . toThrow (
105+ / " c o u n t e r " .* i n i t i a l i z a t i o n /
106+ )
97107 } )
98108
99109 it ( 'catches error thrown in reducer when initializing and re-throw' , ( ) => {
@@ -102,14 +112,16 @@ describe('Utils', () => {
102112 throw new Error ( 'Error thrown in reducer' )
103113 }
104114 } )
105- expect ( ( ) => reducer ( { } ) ) . toThrow ( / E r r o r t h r o w n i n r e d u c e r / )
115+ expect ( ( ) =>
116+ reducer ( undefined , ( undefined as unknown ) as AnyAction )
117+ ) . toThrow ( / E r r o r t h r o w n i n r e d u c e r / )
106118 } )
107119
108120 it ( 'allows a symbol to be used as an action type' , ( ) => {
109121 const increment = Symbol ( 'INCREMENT' )
110122
111123 const reducer = combineReducers ( {
112- counter ( state = 0 , action ) {
124+ counter ( state : number = 0 , action ) {
113125 switch ( action . type ) {
114126 case increment :
115127 return state + 1
@@ -135,7 +147,7 @@ describe('Utils', () => {
135147 }
136148 } )
137149
138- const initialState = reducer ( undefined , '@@INIT' )
150+ const initialState = reducer ( undefined , { type : '@@INIT' } )
139151 expect ( reducer ( initialState , { type : 'FOO' } ) ) . toBe ( initialState )
140152 } )
141153
@@ -144,7 +156,7 @@ describe('Utils', () => {
144156 child1 ( state = { } ) {
145157 return state
146158 } ,
147- child2 ( state = { count : 0 } , action ) {
159+ child2 ( state : { count : number } = { count : 0 } , action ) {
148160 switch ( action . type ) {
149161 case 'increment' :
150162 return { count : state . count + 1 }
@@ -157,15 +169,15 @@ describe('Utils', () => {
157169 }
158170 } )
159171
160- const initialState = reducer ( undefined , '@@INIT' )
172+ const initialState = reducer ( undefined , { type : '@@INIT' } )
161173 expect ( reducer ( initialState , { type : 'increment' } ) ) . not . toBe (
162174 initialState
163175 )
164176 } )
165177
166178 it ( 'throws an error on first call if a reducer attempts to handle a private action' , ( ) => {
167179 const reducer = combineReducers ( {
168- counter ( state , action ) {
180+ counter ( state : number , action ) {
169181 switch ( action . type ) {
170182 case 'increment' :
171183 return state + 1
@@ -179,7 +191,9 @@ describe('Utils', () => {
179191 }
180192 }
181193 } )
182- expect ( ( ) => reducer ( ) ) . toThrow ( / " c o u n t e r " .* p r i v a t e / )
194+ expect ( ( ) =>
195+ reducer ( undefined , ( undefined as unknown ) as AnyAction )
196+ ) . toThrow ( / " c o u n t e r " .* p r i v a t e / )
183197 } )
184198
185199 it ( 'warns if no reducers are passed to combineReducers' , ( ) => {
@@ -188,7 +202,7 @@ describe('Utils', () => {
188202 console . error = spy
189203
190204 const reducer = combineReducers ( { } )
191- reducer ( { } )
205+ reducer ( undefined , { type : '' } )
192206 expect ( spy . mock . calls [ 0 ] [ 0 ] ) . toMatch (
193207 / S t o r e d o e s n o t h a v e a v a l i d r e d u c e r /
194208 )
@@ -200,9 +214,17 @@ describe('Utils', () => {
200214 it ( 'warns if input state does not match reducer shape' , ( ) => {
201215 const preSpy = console . error
202216 const spy = jest . fn ( )
217+ const nullAction = ( undefined as unknown ) as AnyAction
203218 console . error = spy
204219
205- const reducer = combineReducers ( {
220+ interface ShapeState {
221+ foo : { bar : number }
222+ baz : { qux : number }
223+ }
224+
225+ type ShapeMismatchState = CombinedState < ShapeState >
226+
227+ const reducer = combineReducers < ShapeState > ( {
206228 foo ( state = { bar : 1 } ) {
207229 return state
208230 } ,
@@ -211,44 +233,51 @@ describe('Utils', () => {
211233 }
212234 } )
213235
214- reducer ( )
236+ reducer ( undefined , nullAction )
215237 expect ( spy . mock . calls . length ) . toBe ( 0 )
216238
217- reducer ( { foo : { bar : 2 } } )
239+ reducer ( ( { foo : { bar : 2 } } as unknown ) as ShapeState , nullAction )
218240 expect ( spy . mock . calls . length ) . toBe ( 0 )
219241
220- reducer ( {
221- foo : { bar : 2 } ,
222- baz : { qux : 4 }
223- } )
242+ reducer (
243+ {
244+ foo : { bar : 2 } ,
245+ baz : { qux : 4 }
246+ } ,
247+ nullAction
248+ )
224249 expect ( spy . mock . calls . length ) . toBe ( 0 )
225250
226- createStore ( reducer , { bar : 2 } )
251+ createStore ( reducer , ( { bar : 2 } as unknown ) as ShapeState )
227252 expect ( spy . mock . calls [ 0 ] [ 0 ] ) . toMatch (
228253 / U n e x p e c t e d k e y " b a r " .* c r e a t e S t o r e .* i n s t e a d : " f o o " , " b a z " /
229254 )
230255
231- createStore ( reducer , { bar : 2 , qux : 4 , thud : 5 } )
256+ createStore ( reducer , ( {
257+ bar : 2 ,
258+ qux : 4 ,
259+ thud : 5
260+ } as unknown ) as ShapeState )
232261 expect ( spy . mock . calls [ 1 ] [ 0 ] ) . toMatch (
233262 / U n e x p e c t e d k e y s " q u x " , " t h u d " .* c r e a t e S t o r e .* i n s t e a d : " f o o " , " b a z " /
234263 )
235264
236- createStore ( reducer , 1 )
265+ createStore ( reducer , ( 1 as unknown ) as ShapeState )
237266 expect ( spy . mock . calls [ 2 ] [ 0 ] ) . toMatch (
238267 / c r e a t e S t o r e h a s u n e x p e c t e d t y p e o f " N u m b e r " .* k e y s : " f o o " , " b a z " /
239268 )
240269
241- reducer ( { corge : 2 } )
270+ reducer ( ( { corge : 2 } as unknown ) as ShapeState , nullAction )
242271 expect ( spy . mock . calls [ 3 ] [ 0 ] ) . toMatch (
243272 / U n e x p e c t e d k e y " c o r g e " .* r e d u c e r .* i n s t e a d : " f o o " , " b a z " /
244273 )
245274
246- reducer ( { fred : 2 , grault : 4 } )
275+ reducer ( ( { fred : 2 , grault : 4 } as unknown ) as ShapeState , nullAction )
247276 expect ( spy . mock . calls [ 4 ] [ 0 ] ) . toMatch (
248277 / U n e x p e c t e d k e y s " f r e d " , " g r a u l t " .* r e d u c e r .* i n s t e a d : " f o o " , " b a z " /
249278 )
250279
251- reducer ( 1 )
280+ reducer ( ( 1 as unknown ) as ShapeState , nullAction )
252281 expect ( spy . mock . calls [ 5 ] [ 0 ] ) . toMatch (
253282 / r e d u c e r h a s u n e x p e c t e d t y p e o f " N u m b e r " .* k e y s : " f o o " , " b a z " /
254283 )
@@ -261,25 +290,32 @@ describe('Utils', () => {
261290 const preSpy = console . error
262291 const spy = jest . fn ( )
263292 console . error = spy
293+ const nullAction = { type : '' }
264294
265295 const foo = ( state = { foo : 1 } ) => state
266296 const bar = ( state = { bar : 2 } ) => state
267297
268298 expect ( spy . mock . calls . length ) . toBe ( 0 )
269299
300+ interface WarnState {
301+ foo : { foo : number }
302+ bar : { bar : number }
303+ }
304+
270305 const reducer = combineReducers ( { foo, bar } )
271- const state = { foo : 1 , bar : 2 , qux : 3 }
306+ const state = ( { foo : 1 , bar : 2 , qux : 3 } as unknown ) as WarnState
307+ const bazState = ( { ...state , baz : 5 } as unknown ) as WarnState
272308
273- reducer ( state , { } )
274- reducer ( state , { } )
275- reducer ( state , { } )
276- reducer ( state , { } )
309+ reducer ( state , nullAction )
310+ reducer ( state , nullAction )
311+ reducer ( state , nullAction )
312+ reducer ( state , nullAction )
277313 expect ( spy . mock . calls . length ) . toBe ( 1 )
278314
279- reducer ( { ... state , baz : 5 } , { } )
280- reducer ( { ...state , baz : 5 } , { } )
281- reducer ( { ...state , baz : 5 } , { } )
282- reducer ( { ...state , baz : 5 } , { } )
315+ reducer ( bazState , nullAction )
316+ reducer ( { ...bazState } , nullAction )
317+ reducer ( { ...bazState } , nullAction )
318+ reducer ( { ...bazState } , nullAction )
283319 expect ( spy . mock . calls . length ) . toBe ( 2 )
284320
285321 spy . mockClear ( )
0 commit comments