1
1
import { isEqual } from 'lodash' ;
2
- import { createStore } from 'redux' ;
3
- import { BrowserHistory } from 'history' ;
2
+ import { createStore , Reducer , Store , Action , PreloadedState } from 'redux' ;
3
+ import { BrowserHistory , Location , Path } from 'history' ;
4
+ import { ThunkAction } from 'redux-thunk' ;
4
5
5
- interface CreateRouterArg {
6
- store : any ;
7
- reducer : any ;
6
+ export type PlainOrThunk < St , A extends Action < any > > = A | ThunkAction < void , St , { } , A > ;
7
+
8
+ // This is a... dense... attempt at saying "we accept any store with
9
+ // any dispatch so long as it can handle the actions you create". It's
10
+ // probably overly complicated, restrictive, and broad all at the same
11
+ // time.
12
+ interface CreateRouterArg < St , SubSt , A extends Action < any > > {
13
+ store : Store < St , A > & { dispatch : ( a : PlainOrThunk < St , A > ) => void } ; // |
14
+ reducer : Reducer < St > ;
8
15
history : BrowserHistory ;
9
- stateSelector : any ;
10
- stateToLocation : any ;
11
- locationToAction : any ;
16
+ stateSelector : ( state : St ) => SubSt ;
17
+ stateToLocation : ( substate : St ) => Partial < Path > ;
18
+ locationToAction : ( location : Location ) => PlainOrThunk < St , A > | null ;
12
19
}
13
20
14
21
export interface RouterObject {
15
22
provisionalLocation : any ;
16
23
}
17
24
18
- export function createRouter ( {
25
+ export function createRouter < St , SubSt , A extends Action < any > > ( {
19
26
store,
20
27
reducer,
21
28
history,
22
29
stateSelector,
23
30
stateToLocation,
24
31
locationToAction,
25
- } : CreateRouterArg ) : RouterObject {
32
+ } : CreateRouterArg < St , SubSt , A > ) : RouterObject {
26
33
let doingUpdateFromBrowser = false ; // Avoid immediately PUSHing the state again
27
- let interestingPrevState ;
34
+ let interestingPrevState : SubSt ;
28
35
29
36
// Watch changes to the Redux state
30
37
store . subscribe ( ( ) => {
@@ -42,7 +49,7 @@ export function createRouter({
42
49
}
43
50
} ) ;
44
51
45
- const dispatchBrowserLocationChange = nextLocation => {
52
+ const dispatchBrowserLocationChange = ( nextLocation : Location ) => {
46
53
const action = locationToAction ( nextLocation ) ;
47
54
if ( action ) {
48
55
doingUpdateFromBrowser = true ;
@@ -66,11 +73,13 @@ export function createRouter({
66
73
interestingPrevState = stateSelector ( store . getState ( ) ) ;
67
74
68
75
return {
69
- provisionalLocation : action => {
76
+ provisionalLocation : ( makeAction : ( ) => A ) => {
70
77
const state = store . getState ( ) ;
71
- const tempStore = createStore ( reducer , state ) ;
72
- const a = action ( ) ;
73
- tempStore . dispatch ( a ) ;
78
+ // This is a hack -- we know that our fully-constructed state is
79
+ // valid as a "preloaded" state for a brand new store!
80
+ const tempStore = createStore ( reducer , state as PreloadedState < St > ) ;
81
+ const action = makeAction ( ) ;
82
+ tempStore . dispatch ( action ) ;
74
83
const maybeState = tempStore . getState ( ) ;
75
84
return stateToLocation ( maybeState ) ;
76
85
} ,
0 commit comments