1 | import {
|
2 | createStore,
|
3 | compose,
|
4 | applyMiddleware,
|
5 | combineReducers,
|
6 | Reducer,
|
7 | ReducersMapObject,
|
8 | Middleware,
|
9 | Action,
|
10 | AnyAction,
|
11 | StoreEnhancer,
|
12 | Store,
|
13 | DeepPartial,
|
14 | Dispatch
|
15 | } from 'redux'
|
16 | import {
|
17 | composeWithDevTools,
|
18 | EnhancerOptions as DevToolsOptions
|
19 | } from './devtoolsExtension'
|
20 |
|
21 | import isPlainObject from './isPlainObject'
|
22 | import {
|
23 | ThunkMiddlewareFor,
|
24 | curryGetDefaultMiddleware,
|
25 | CurriedGetDefaultMiddleware
|
26 | } from './getDefaultMiddleware'
|
27 | import { DispatchForMiddlewares } from './tsHelpers'
|
28 |
|
29 | const IS_PRODUCTION = process.env.NODE_ENV === 'production'
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 | export type ConfigureEnhancersCallback = (
|
37 | defaultEnhancers: StoreEnhancer[]
|
38 | ) => StoreEnhancer[]
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 | export interface ConfigureStoreOptions<
|
46 | S = any,
|
47 | A extends Action = AnyAction,
|
48 | M extends Middlewares<S> = Middlewares<S>
|
49 | > {
|
50 | |
51 |
|
52 |
|
53 |
|
54 | reducer: Reducer<S, A> | ReducersMapObject<S, A>
|
55 |
|
56 | |
57 |
|
58 |
|
59 |
|
60 | middleware?: ((getDefaultMiddleware: CurriedGetDefaultMiddleware<S>) => M) | M
|
61 |
|
62 | /**
|
63 | * Whether to enable Redux DevTools integration. Defaults to `true`.
|
64 | *
|
65 | * Additional configuration can be done by passing Redux DevTools options
|
66 | */
|
67 | devTools?: boolean | DevToolsOptions
|
68 |
|
69 | /**
|
70 | * The initial state, same as Redux's createStore.
|
71 | * You may optionally specify it to hydrate the state
|
72 | * from the server in universal apps, or to restore a previously serialized
|
73 | * user session. If you use `combineReducers()` to produce the root reducer
|
74 | * function (either directly or indirectly by passing an object as `reducer`),
|
75 | * this must be an object with the same shape as the reducer map keys.
|
76 | */
|
77 | // NOTE: The needlessly complicated `S extends any ? S : S` instead of just
|
78 | // `S` ensures that the TypeScript compiler doesn't attempt to infer `S`
|
79 | // based on the value passed as `preloadedState`, which might be a partial
|
80 | // state rather than the full thing.
|
81 | preloadedState?: DeepPartial<S extends any ? S : S>
|
82 |
|
83 | /**
|
84 | * The store enhancers to apply. See Redux's `createStore()`.
|
85 | * All enhancers will be included before the DevTools Extension enhancer.
|
86 | * If you need to customize the order of enhancers, supply a callback
|
87 | * function that will receive the original array (ie, `[applyMiddleware]`),
|
88 | * and should return a new array (such as `[applyMiddleware, offline]`).
|
89 | * If you only need to add middleware, you can use the `middleware` parameter instead.
|
90 | */
|
91 | enhancers?: StoreEnhancer[] | ConfigureEnhancersCallback
|
92 | }
|
93 |
|
94 | type Middlewares<S> = ReadonlyArray<Middleware<{}, S>>
|
95 |
|
96 | /**
|
97 | * A Redux store returned by `configureStore()`. Supports dispatching
|
98 | * side-effectful _thunks_ in addition to plain actions.
|
99 | *
|
100 | * @public
|
101 | */
|
102 | export interface EnhancedStore<
|
103 | S = any,
|
104 | A extends Action = AnyAction,
|
105 | M extends Middlewares<S> = Middlewares<S>
|
106 | > extends Store<S, A> {
|
107 | /**
|
108 | * The `dispatch` method of your store, enhanced by all its middlewares.
|
109 | *
|
110 | * @inheritdoc
|
111 | */
|
112 | dispatch: DispatchForMiddlewares<M> & Dispatch<A>
|
113 | }
|
114 |
|
115 | /**
|
116 | * A friendly abstraction over the standard Redux `createStore()` function.
|
117 | *
|
118 | * @param config The store configuration.
|
119 | * @returns A configured Redux store.
|
120 | *
|
121 | * @public
|
122 | */
|
123 | export function configureStore<
|
124 | S = any,
|
125 | A extends Action = AnyAction,
|
126 | M extends Middlewares<S> = [ThunkMiddlewareFor<S>]
|
127 | >(options: ConfigureStoreOptions<S, A, M>): EnhancedStore<S, A, M> {
|
128 | const curriedGetDefaultMiddleware = curryGetDefaultMiddleware<S>()
|
129 |
|
130 | const {
|
131 | reducer = undefined,
|
132 | middleware = curriedGetDefaultMiddleware(),
|
133 | devTools = true,
|
134 | preloadedState = undefined,
|
135 | enhancers = undefined
|
136 | } = options || {}
|
137 |
|
138 | let rootReducer: Reducer<S, A>
|
139 |
|
140 | if (typeof reducer === 'function') {
|
141 | rootReducer = reducer
|
142 | } else if (isPlainObject(reducer)) {
|
143 | rootReducer = combineReducers(reducer)
|
144 | } else {
|
145 | throw new Error(
|
146 | '"reducer" is a required argument, and must be a function or an object of functions that can be passed to combineReducers'
|
147 | )
|
148 | }
|
149 |
|
150 | const middlewareEnhancer = applyMiddleware(
|
151 | ...(typeof middleware === 'function'
|
152 | ? middleware(curriedGetDefaultMiddleware)
|
153 | : middleware)
|
154 | )
|
155 |
|
156 | let finalCompose = compose
|
157 |
|
158 | if (devTools) {
|
159 | finalCompose = composeWithDevTools({
|
160 |
|
161 | trace: !IS_PRODUCTION,
|
162 | ...(typeof devTools === 'object' && devTools)
|
163 | })
|
164 | }
|
165 |
|
166 | let storeEnhancers: StoreEnhancer[] = [middlewareEnhancer]
|
167 |
|
168 | if (Array.isArray(enhancers)) {
|
169 | storeEnhancers = [middlewareEnhancer, ...enhancers]
|
170 | } else if (typeof enhancers === 'function') {
|
171 | storeEnhancers = enhancers(storeEnhancers)
|
172 | }
|
173 |
|
174 | const composedEnhancer = finalCompose(...storeEnhancers) as any
|
175 |
|
176 | return createStore(rootReducer, preloadedState as any, composedEnhancer)
|
177 | }
|
178 |
|
\ | No newline at end of file |