1 | import { Action, UnknownAction } from './actions'
|
2 | import { Reducer } from './reducers'
|
3 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
|
4 | import _$$observable from '../utils/symbol-observable'
|
5 |
|
6 | /**
|
7 | * A *dispatching function* (or simply *dispatch function*) is a function that
|
8 | * accepts an action or an async action; it then may or may not dispatch one
|
9 | * or more actions to the store.
|
10 | *
|
11 | * We must distinguish between dispatching functions in general and the base
|
12 | * `dispatch` function provided by the store instance without any middleware.
|
13 | *
|
14 | * The base dispatch function *always* synchronously sends an action to the
|
15 | * store's reducer, along with the previous state returned by the store, to
|
16 | * calculate a new state. It expects actions to be plain objects ready to be
|
17 | * consumed by the reducer.
|
18 | *
|
19 | * Middleware wraps the base dispatch function. It allows the dispatch
|
20 | * function to handle async actions in addition to actions. Middleware may
|
21 | * transform, delay, ignore, or otherwise interpret actions or async actions
|
22 | * before passing them to the next middleware.
|
23 | *
|
24 | * @template A The type of things (actions or otherwise) which may be
|
25 | * dispatched.
|
26 | */
|
27 | export interface Dispatch<A extends Action = UnknownAction> {
|
28 | <T extends A>(action: T, ...extraArgs: any[]): T
|
29 | }
|
30 |
|
31 | /**
|
32 | * Function to remove listener added by `Store.subscribe()`.
|
33 | */
|
34 | export interface Unsubscribe {
|
35 | (): void
|
36 | }
|
37 |
|
38 | export type ListenerCallback = () => void
|
39 |
|
40 | declare global {
|
41 | interface SymbolConstructor {
|
42 | readonly observable: symbol
|
43 | }
|
44 | }
|
45 |
|
46 | /**
|
47 | * A minimal observable of state changes.
|
48 | * For more information, see the observable proposal:
|
49 | * https://github.com/tc39/proposal-observable
|
50 | */
|
51 | export type Observable<T> = {
|
52 | /**
|
53 | * The minimal observable subscription method.
|
54 | * @param {Object} observer Any object that can be used as an observer.
|
55 | * The observer object should have a `next` method.
|
56 | * @returns {subscription} An object with an `unsubscribe` method that can
|
57 | * be used to unsubscribe the observable from the store, and prevent further
|
58 | * emission of values from the observable.
|
59 | */
|
60 | subscribe: (observer: Observer<T>) => { unsubscribe: Unsubscribe }
|
61 | [Symbol.observable](): Observable<T>
|
62 | }
|
63 |
|
64 | /**
|
65 | * An Observer is used to receive data from an Observable, and is supplied as
|
66 | * an argument to subscribe.
|
67 | */
|
68 | export type Observer<T> = {
|
69 | next?(value: T): void
|
70 | }
|
71 |
|
72 | /**
|
73 | * A store is an object that holds the application's state tree.
|
74 | * There should only be a single store in a Redux app, as the composition
|
75 | * happens on the reducer level.
|
76 | *
|
77 | * @template S The type of state held by this store.
|
78 | * @template A the type of actions which may be dispatched by this store.
|
79 | * @template StateExt any extension to state from store enhancers
|
80 | */
|
81 | export interface Store<
|
82 | S = any,
|
83 | A extends Action = UnknownAction,
|
84 | StateExt extends unknown = unknown
|
85 | > {
|
86 | /**
|
87 | * Dispatches an action. It is the only way to trigger a state change.
|
88 | *
|
89 | * The `reducer` function, used to create the store, will be called with the
|
90 | * current state tree and the given `action`. Its return value will be
|
91 | * considered the **next** state of the tree, and the change listeners will
|
92 | * be notified.
|
93 | *
|
94 | * The base implementation only supports plain object actions. If you want
|
95 | * to dispatch a Promise, an Observable, a thunk, or something else, you
|
96 | * need to wrap your store creating function into the corresponding
|
97 | * middleware. For example, see the documentation for the `redux-thunk`
|
98 | * package. Even the middleware will eventually dispatch plain object
|
99 | * actions using this method.
|
100 | *
|
101 | * @param action A plain object representing “what changed”. It is a good
|
102 | * idea to keep actions serializable so you can record and replay user
|
103 | * sessions, or use the time travelling `redux-devtools`. An action must
|
104 | * have a `type` property which may not be `undefined`. It is a good idea
|
105 | * to use string constants for action types.
|
106 | *
|
107 | * @returns For convenience, the same action object you dispatched.
|
108 | *
|
109 | * Note that, if you use a custom middleware, it may wrap `dispatch()` to
|
110 | * return something else (for example, a Promise you can await).
|
111 | */
|
112 | dispatch: Dispatch<A>
|
113 |
|
114 | /**
|
115 | * Reads the state tree managed by the store.
|
116 | *
|
117 | * @returns The current state tree of your application.
|
118 | */
|
119 | getState(): S & StateExt
|
120 |
|
121 | /**
|
122 | * Adds a change listener. It will be called any time an action is
|
123 | * dispatched, and some part of the state tree may potentially have changed.
|
124 | * You may then call `getState()` to read the current state tree inside the
|
125 | * callback.
|
126 | *
|
127 | * You may call `dispatch()` from a change listener, with the following
|
128 | * caveats:
|
129 | *
|
130 | * 1. The subscriptions are snapshotted just before every `dispatch()` call.
|
131 | * If you subscribe or unsubscribe while the listeners are being invoked,
|
132 | * this will not have any effect on the `dispatch()` that is currently in
|
133 | * progress. However, the next `dispatch()` call, whether nested or not,
|
134 | * will use a more recent snapshot of the subscription list.
|
135 | *
|
136 | * 2. The listener should not expect to see all states changes, as the state
|
137 | * might have been updated multiple times during a nested `dispatch()` before
|
138 | * the listener is called. It is, however, guaranteed that all subscribers
|
139 | * registered before the `dispatch()` started will be called with the latest
|
140 | * state by the time it exits.
|
141 | *
|
142 | * @param listener A callback to be invoked on every dispatch.
|
143 | * @returns A function to remove this change listener.
|
144 | */
|
145 | subscribe(listener: ListenerCallback): Unsubscribe
|
146 |
|
147 | /**
|
148 | * Replaces the reducer currently used by the store to calculate the state.
|
149 | *
|
150 | * You might need this if your app implements code splitting and you want to
|
151 | * load some of the reducers dynamically. You might also need this if you
|
152 | * implement a hot reloading mechanism for Redux.
|
153 | *
|
154 | * @param nextReducer The reducer for the store to use instead.
|
155 | */
|
156 | replaceReducer(nextReducer: Reducer<S, A>): void
|
157 |
|
158 | /**
|
159 | * Interoperability point for observable/reactive libraries.
|
160 | * @returns {observable} A minimal observable of state changes.
|
161 | * For more information, see the observable proposal:
|
162 | * https://github.com/tc39/proposal-observable
|
163 | */
|
164 | [Symbol.observable](): Observable<S & StateExt>
|
165 | }
|
166 |
|
167 | export type UnknownIfNonSpecific<T> = {} extends T ? unknown : T
|
168 |
|
169 | /**
|
170 | * A store creator is a function that creates a Redux store. Like with
|
171 | * dispatching function, we must distinguish the base store creator,
|
172 | * `createStore(reducer, preloadedState)` exported from the Redux package, from
|
173 | * store creators that are returned from the store enhancers.
|
174 | *
|
175 | * @template S The type of state to be held by the store.
|
176 | * @template A The type of actions which may be dispatched.
|
177 | * @template PreloadedState The initial state that is passed into the reducer.
|
178 | * @template Ext Store extension that is mixed in to the Store type.
|
179 | * @template StateExt State extension that is mixed into the state type.
|
180 | */
|
181 | export interface StoreCreator {
|
182 | <S, A extends Action, Ext extends {} = {}, StateExt extends {} = {}>(
|
183 | reducer: Reducer<S, A>,
|
184 | enhancer?: StoreEnhancer<Ext, StateExt>
|
185 | ): Store<S, A, UnknownIfNonSpecific<StateExt>> & Ext
|
186 | <
|
187 | S,
|
188 | A extends Action,
|
189 | Ext extends {} = {},
|
190 | StateExt extends {} = {},
|
191 | PreloadedState = S
|
192 | >(
|
193 | reducer: Reducer<S, A, PreloadedState>,
|
194 | preloadedState?: PreloadedState | undefined,
|
195 | enhancer?: StoreEnhancer<Ext>
|
196 | ): Store<S, A, UnknownIfNonSpecific<StateExt>> & Ext
|
197 | }
|
198 |
|
199 | /**
|
200 | * A store enhancer is a higher-order function that composes a store creator
|
201 | * to return a new, enhanced store creator. This is similar to middleware in
|
202 | * that it allows you to alter the store interface in a composable way.
|
203 | *
|
204 | * Store enhancers are much the same concept as higher-order components in
|
205 | * React, which are also occasionally called “component enhancers”.
|
206 | *
|
207 | * Because a store is not an instance, but rather a plain-object collection of
|
208 | * functions, copies can be easily created and modified without mutating the
|
209 | * original store. There is an example in `compose` documentation
|
210 | * demonstrating that.
|
211 | *
|
212 | * Most likely you'll never write a store enhancer, but you may use the one
|
213 | * provided by the developer tools. It is what makes time travel possible
|
214 | * without the app being aware it is happening. Amusingly, the Redux
|
215 | * middleware implementation is itself a store enhancer.
|
216 | *
|
217 | * @template Ext Store extension that is mixed into the Store type.
|
218 | * @template StateExt State extension that is mixed into the state type.
|
219 | */
|
220 | export type StoreEnhancer<Ext extends {} = {}, StateExt extends {} = {}> = <
|
221 | NextExt extends {},
|
222 | NextStateExt extends {}
|
223 | >(
|
224 | next: StoreEnhancerStoreCreator<NextExt, NextStateExt>
|
225 | ) => StoreEnhancerStoreCreator<NextExt & Ext, NextStateExt & StateExt>
|
226 | export type StoreEnhancerStoreCreator<
|
227 | Ext extends {} = {},
|
228 | StateExt extends {} = {}
|
229 | > = <S, A extends Action, PreloadedState>(
|
230 | reducer: Reducer<S, A, PreloadedState>,
|
231 | preloadedState?: PreloadedState | undefined
|
232 | ) => Store<S, A, StateExt> & Ext
|