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