@@ -3,29 +3,35 @@ import { useReduxContext as useDefaultReduxContext } from './useReduxContext'
3
3
import Subscription from '../utils/Subscription'
4
4
import { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect'
5
5
import { ReactReduxContext } from '../components/Context'
6
+ import { AnyAction , Store } from 'redux'
7
+ import { DefaultRootState } from '../types'
6
8
7
- const refEquality = ( a , b ) => a === b
9
+ type EqualityFn < T > = ( a : T | undefined , b : T | undefined ) => boolean ;
8
10
9
- function useSelectorWithStoreAndSubscription (
10
- selector ,
11
- equalityFn ,
12
- store ,
13
- contextSub
14
- ) {
11
+ const refEquality : EqualityFn < any > = ( a , b ) => a === b
12
+
13
+ type TSelector < S , R > = ( state : S ) => R ;
14
+
15
+ function useSelectorWithStoreAndSubscription < TStoreState , TSelectedState > (
16
+ selector : TSelector < TStoreState , TSelectedState > ,
17
+ equalityFn : EqualityFn < TSelectedState > ,
18
+ store : Store < TStoreState , AnyAction > ,
19
+ contextSub : Subscription
20
+ ) : TSelectedState {
15
21
const [ , forceRender ] = useReducer ( ( s ) => s + 1 , 0 )
16
22
17
23
const subscription = useMemo ( ( ) => new Subscription ( store , contextSub ) , [
18
24
store ,
19
25
contextSub ,
20
26
] )
21
27
22
- const latestSubscriptionCallbackError = useRef ( )
23
- const latestSelector = useRef ( )
24
- const latestStoreState = useRef ( )
25
- const latestSelectedState = useRef ( )
28
+ const latestSubscriptionCallbackError = useRef < Error > ( )
29
+ const latestSelector = useRef < TSelector < TStoreState , TSelectedState > > ( )
30
+ const latestStoreState = useRef < TStoreState > ( )
31
+ const latestSelectedState = useRef < TSelectedState > ( )
26
32
27
33
const storeState = store . getState ( )
28
- let selectedState
34
+ let selectedState : TSelectedState | undefined
29
35
30
36
try {
31
37
if (
@@ -65,7 +71,7 @@ function useSelectorWithStoreAndSubscription(
65
71
function checkForUpdates ( ) {
66
72
try {
67
73
const newStoreState = store . getState ( )
68
- const newSelectedState = latestSelector . current ( newStoreState )
74
+ const newSelectedState = latestSelector . current ! ( newStoreState )
69
75
70
76
if ( equalityFn ( newSelectedState , latestSelectedState . current ) ) {
71
77
return
@@ -92,7 +98,7 @@ function useSelectorWithStoreAndSubscription(
92
98
return ( ) => subscription . tryUnsubscribe ( )
93
99
} , [ store , subscription ] )
94
100
95
- return selectedState
101
+ return selectedState !
96
102
}
97
103
98
104
/**
@@ -101,12 +107,13 @@ function useSelectorWithStoreAndSubscription(
101
107
* @param {React.Context } [context=ReactReduxContext] Context passed to your `<Provider>`.
102
108
* @returns {Function } A `useSelector` hook bound to the specified context.
103
109
*/
104
- export function createSelectorHook ( context = ReactReduxContext ) {
110
+ export function createSelectorHook ( context = ReactReduxContext ) : < TState = DefaultRootState , Selected = unknown > ( selector : ( state : TState ) => Selected , equalityFn ?: EqualityFn < Selected > ) => Selected {
105
111
const useReduxContext =
106
112
context === ReactReduxContext
107
113
? useDefaultReduxContext
108
114
: ( ) => useContext ( context )
109
- return function useSelector ( selector , equalityFn = refEquality ) {
115
+
116
+ return function useSelector < TState , Selected extends unknown > ( selector : ( state : TState ) => Selected , equalityFn : EqualityFn < Selected > = refEquality ) : Selected {
110
117
if ( process . env . NODE_ENV !== 'production' ) {
111
118
if ( ! selector ) {
112
119
throw new Error ( `You must pass a selector to useSelector` )
@@ -120,7 +127,7 @@ export function createSelectorHook(context = ReactReduxContext) {
120
127
)
121
128
}
122
129
}
123
- const { store, subscription : contextSub } = useReduxContext ( )
130
+ const { store, subscription : contextSub } = useReduxContext ( ) !
124
131
125
132
const selectedState = useSelectorWithStoreAndSubscription (
126
133
selector ,
0 commit comments