@@ -11,28 +11,46 @@ import {
11
11
connect ,
12
12
createSelectorHook ,
13
13
} from '../../src/index'
14
+ import type { FunctionComponent } from 'react'
14
15
import { useReduxContext } from '../../src/hooks/useReduxContext'
15
-
16
+ import type { Store } from 'redux'
17
+ import type { ProviderProps } from '../../src/'
18
+ import type { Subscription } from '../../src/utils/Subscription'
19
+
20
+ type PropsTypeDelStore = Omit < ProviderProps , 'store' >
21
+ type DefaultRootState = {
22
+ count : number
23
+ }
16
24
describe ( 'React' , ( ) => {
17
25
describe ( 'hooks' , ( ) => {
18
26
describe ( 'useSelector' , ( ) => {
19
- let store
27
+ let store : Store
20
28
let renderedItems = [ ]
21
29
22
30
beforeEach ( ( ) => {
23
- store = createStore ( ( { count } = { count : - 1 } ) => ( {
24
- count : count + 1 ,
25
- } ) )
31
+ interface ReducerState {
32
+ count : number
33
+ }
34
+ store = createStore (
35
+ ( { count } : ReducerState = { count : - 1 } ) : ReducerState => ( {
36
+ count : count + 1 ,
37
+ } )
38
+ )
26
39
renderedItems = [ ]
27
40
} )
28
41
29
42
afterEach ( ( ) => rtl . cleanup ( ) )
30
43
31
44
describe ( 'core subscription behavior' , ( ) => {
32
45
it ( 'selects the state on initial render' , ( ) => {
33
- const { result } = renderHook ( ( ) => useSelector ( ( s ) => s . count ) , {
34
- wrapper : ( props ) => < ProviderMock { ...props } store = { store } /> ,
35
- } )
46
+ const { result } = renderHook (
47
+ ( ) => useSelector < DefaultRootState > ( ( s ) => s . count ) ,
48
+ {
49
+ wrapper : ( props : PropsTypeDelStore ) => (
50
+ < ProviderMock { ...props } store = { store } />
51
+ ) ,
52
+ }
53
+ )
36
54
37
55
expect ( result . current ) . toEqual ( 0 )
38
56
} )
@@ -41,7 +59,9 @@ describe('React', () => {
41
59
const selector = jest . fn ( ( s ) => s . count )
42
60
43
61
const { result } = renderHook ( ( ) => useSelector ( selector ) , {
44
- wrapper : ( props ) => < ProviderMock { ...props } store = { store } /> ,
62
+ wrapper : ( props : PropsTypeDelStore ) => (
63
+ < ProviderMock { ...props } store = { store } />
64
+ ) ,
45
65
} )
46
66
47
67
expect ( result . current ) . toEqual ( 0 )
@@ -58,7 +78,7 @@ describe('React', () => {
58
78
59
79
describe ( 'lifecycle interactions' , ( ) => {
60
80
it ( 'always uses the latest state' , ( ) => {
61
- store = createStore ( ( c ) => c + 1 , - 1 )
81
+ store = createStore ( ( c : number ) : number => c + 1 , - 1 )
62
82
63
83
const Comp = ( ) => {
64
84
const selector = useCallback ( ( c ) => c + 1 , [ ] )
@@ -81,17 +101,17 @@ describe('React', () => {
81
101
} )
82
102
83
103
it ( 'subscribes to the store synchronously' , ( ) => {
84
- let rootSubscription
104
+ let rootSubscription : Subscription
85
105
86
106
const Parent = ( ) => {
87
107
const { subscription } = useReduxContext ( )
88
108
rootSubscription = subscription
89
- const count = useSelector ( ( s ) => s . count )
109
+ const count = useSelector < DefaultRootState > ( ( s ) => s . count )
90
110
return count === 1 ? < Child /> : null
91
111
}
92
112
93
113
const Child = ( ) => {
94
- const count = useSelector ( ( s ) => s . count )
114
+ const count = useSelector < DefaultRootState > ( ( s ) => s . count )
95
115
return < div > { count } </ div >
96
116
}
97
117
@@ -109,17 +129,17 @@ describe('React', () => {
109
129
} )
110
130
111
131
it ( 'unsubscribes when the component is unmounted' , ( ) => {
112
- let rootSubscription
132
+ let rootSubscription : Subscription
113
133
114
134
const Parent = ( ) => {
115
135
const { subscription } = useReduxContext ( )
116
136
rootSubscription = subscription
117
- const count = useSelector ( ( s ) => s . count )
137
+ const count = useSelector < DefaultRootState > ( ( s ) => s . count )
118
138
return count === 0 ? < Child /> : null
119
139
}
120
140
121
141
const Child = ( ) => {
122
- const count = useSelector ( ( s ) => s . count )
142
+ const count = useSelector < DefaultRootState > ( ( s ) => s . count )
123
143
return < div > { count } </ div >
124
144
}
125
145
@@ -138,7 +158,7 @@ describe('React', () => {
138
158
139
159
it ( 'notices store updates between render and store subscription effect' , ( ) => {
140
160
const Comp = ( ) => {
141
- const count = useSelector ( ( s ) => s . count )
161
+ const count = useSelector < DefaultRootState > ( ( s ) => s . count )
142
162
renderedItems . push ( count )
143
163
144
164
// I don't know a better way to trigger a store update before the
@@ -161,7 +181,7 @@ describe('React', () => {
161
181
} )
162
182
163
183
it ( 'works properly with memoized selector with dispatch in Child useLayoutEffect' , ( ) => {
164
- store = createStore ( ( c ) => c + 1 , - 1 )
184
+ store = createStore ( ( c : number ) => c + 1 , - 1 )
165
185
166
186
const Comp = ( ) => {
167
187
const selector = useCallback ( ( c ) => c , [ ] )
@@ -221,8 +241,14 @@ describe('React', () => {
221
241
} )
222
242
223
243
it ( 'allows other equality functions to prevent unnecessary updates' , ( ) => {
244
+ interface ReducerParamsType {
245
+ count : number
246
+ stable : any
247
+ }
224
248
store = createStore (
225
- ( { count, stable } = { count : - 1 , stable : { } } ) => ( {
249
+ (
250
+ { count, stable } : ReducerParamsType = { count : - 1 , stable : { } }
251
+ ) => ( {
226
252
count : count + 1 ,
227
253
stable,
228
254
} )
@@ -286,12 +312,12 @@ describe('React', () => {
286
312
const spy = jest . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } )
287
313
288
314
const Parent = ( ) => {
289
- const count = useSelector ( ( s ) => s . count )
315
+ const count = useSelector < DefaultRootState > ( ( s ) => s . count )
290
316
return < Child parentCount = { count } />
291
317
}
292
318
293
319
const Child = ( { parentCount } ) => {
294
- const result = useSelector ( ( { count } ) => {
320
+ const result = useSelector < DefaultRootState > ( ( { count } ) => {
295
321
if ( count !== parentCount ) {
296
322
throw new Error ( )
297
323
}
@@ -328,7 +354,7 @@ describe('React', () => {
328
354
return < div > { result } </ div >
329
355
}
330
356
331
- const store = createStore ( ( count = - 1 ) => count + 1 )
357
+ const store = createStore ( ( count : number = - 1 ) => count + 1 )
332
358
333
359
const App = ( ) => (
334
360
< ProviderMock store = { store } >
@@ -349,12 +375,12 @@ describe('React', () => {
349
375
const spy = jest . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } )
350
376
351
377
const Parent = ( ) => {
352
- const count = useSelector ( ( s ) => s . count )
378
+ const count = useSelector < DefaultRootState > ( ( s ) => s . count )
353
379
return < Child parentCount = { count } />
354
380
}
355
381
356
382
const Child = ( { parentCount } ) => {
357
- const result = useSelector ( ( { count } ) => {
383
+ const result = useSelector < DefaultRootState > ( ( { count } ) => {
358
384
if ( parentCount > 0 ) {
359
385
throw new Error ( )
360
386
}
@@ -380,20 +406,30 @@ describe('React', () => {
380
406
const spy = jest . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } )
381
407
382
408
const Parent = ( ) => {
383
- const count = useSelector ( ( s ) => s . count )
409
+ const count = useSelector < DefaultRootState , number > ( ( s ) => s . count )
384
410
return < ConnectedWrapper parentCount = { count } />
385
411
}
386
-
387
- const ConnectedWrapper = connect ( ( { count } ) => ( { count } ) ) (
388
- ( { parentCount } ) => {
389
- return < Child parentCount = { parentCount } />
390
- }
391
- )
412
+ interface ParentContentProps {
413
+ parentCount : number
414
+ }
415
+ const ConnectedWrapper = connect <
416
+ DefaultRootState ,
417
+ undefined ,
418
+ ParentContentProps ,
419
+ DefaultRootState
420
+ > ( ( { count } ) => ( {
421
+ count,
422
+ } ) ) < FunctionComponent < ParentContentProps > > ( ( { parentCount } ) => {
423
+ return < Child parentCount = { parentCount } />
424
+ } )
392
425
393
426
let sawInconsistentState = false
394
427
395
- const Child = ( { parentCount } ) => {
396
- const result = useSelector ( ( { count } ) => {
428
+ interface ChildPropsType {
429
+ parentCount : number
430
+ }
431
+ const Child = ( { parentCount } : ChildPropsType ) => {
432
+ const result = useSelector < DefaultRootState > ( ( { count } ) => {
397
433
if ( count !== parentCount ) {
398
434
sawInconsistentState = true
399
435
}
@@ -418,15 +454,17 @@ describe('React', () => {
418
454
} )
419
455
420
456
it ( 'reuse latest selected state on selector re-run' , ( ) => {
421
- store = createStore ( ( { count } = { count : - 1 } ) => ( {
422
- count : count + 1 ,
423
- } ) )
457
+ store = createStore (
458
+ ( { count } : DefaultRootState = { count : - 1 } ) => ( {
459
+ count : count + 1 ,
460
+ } )
461
+ )
424
462
425
463
const alwaysEqual = ( ) => true
426
464
427
465
const Comp = ( ) => {
428
466
// triggers render on store change
429
- useSelector ( ( s ) => s . count )
467
+ useSelector < DefaultRootState > ( ( s ) => s . count )
430
468
const array = useSelector ( ( ) => [ 1 , 2 , 3 ] , alwaysEqual )
431
469
renderedItems . push ( array )
432
470
return < div />
@@ -449,15 +487,20 @@ describe('React', () => {
449
487
450
488
describe ( 'error handling for invalid arguments' , ( ) => {
451
489
it ( 'throws if no selector is passed' , ( ) => {
490
+ //@ts -expect-error
452
491
expect ( ( ) => useSelector ( ) ) . toThrow ( )
453
492
} )
454
493
455
494
it ( 'throws if selector is not a function' , ( ) => {
495
+ //@ts -expect-error
456
496
expect ( ( ) => useSelector ( 1 ) ) . toThrow ( )
457
497
} )
458
498
459
499
it ( 'throws if equality function is not a function' , ( ) => {
460
- expect ( ( ) => useSelector ( ( s ) => s . count , 1 ) ) . toThrow ( )
500
+ expect ( ( ) =>
501
+ //@ts -expect-error
502
+ useSelector < DefaultRootState > ( ( s ) => s . count , 1 )
503
+ ) . toThrow ( )
461
504
} )
462
505
} )
463
506
} )
@@ -467,12 +510,16 @@ describe('React', () => {
467
510
let customStore
468
511
469
512
beforeEach ( ( ) => {
470
- defaultStore = createStore ( ( { count } = { count : - 1 } ) => ( {
471
- count : count + 1 ,
472
- } ) )
473
- customStore = createStore ( ( { count } = { count : 10 } ) => ( {
474
- count : count + 2 ,
475
- } ) )
513
+ defaultStore = createStore (
514
+ ( { count } : DefaultRootState = { count : - 1 } ) => ( {
515
+ count : count + 1 ,
516
+ } )
517
+ )
518
+ customStore = createStore (
519
+ ( { count } : DefaultRootState = { count : 10 } ) => ( {
520
+ count : count + 2 ,
521
+ } )
522
+ )
476
523
} )
477
524
478
525
it ( 'subscribes to the correct store' , ( ) => {
@@ -481,15 +528,15 @@ describe('React', () => {
481
528
let defaultCount = null
482
529
let customCount = null
483
530
484
- const getCount = ( s ) => s . count
531
+ const getCount = ( s : DefaultRootState ) => s . count
485
532
486
533
const DisplayDefaultCount = ( { children = null } ) => {
487
- const count = useSelector ( getCount )
534
+ const count = useSelector < DefaultRootState > ( getCount )
488
535
defaultCount = count
489
536
return < > { children } </ >
490
537
}
491
538
const DisplayCustomCount = ( { children = null } ) => {
492
- const count = useCustomSelector ( getCount )
539
+ const count = useCustomSelector < DefaultRootState > ( getCount )
493
540
customCount = count
494
541
return < > { children } </ >
495
542
}
0 commit comments