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