createReducer.d.ts 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import type { Draft } from 'immer';
  2. import type { AnyAction, Action, Reducer } from 'redux';
  3. import type { ActionReducerMapBuilder } from './mapBuilders';
  4. import type { NoInfer } from './tsHelpers';
  5. /**
  6. * Defines a mapping from action types to corresponding action object shapes.
  7. *
  8. * @deprecated This should not be used manually - it is only used for internal
  9. * inference purposes and should not have any further value.
  10. * It might be removed in the future.
  11. * @public
  12. */
  13. export declare type Actions<T extends keyof any = string> = Record<T, Action>;
  14. /**
  15. * @deprecated use `TypeGuard` instead
  16. */
  17. export interface ActionMatcher<A extends AnyAction> {
  18. (action: AnyAction): action is A;
  19. }
  20. export declare type ActionMatcherDescription<S, A extends AnyAction> = {
  21. matcher: ActionMatcher<A>;
  22. reducer: CaseReducer<S, NoInfer<A>>;
  23. };
  24. export declare type ReadonlyActionMatcherDescriptionCollection<S> = ReadonlyArray<ActionMatcherDescription<S, any>>;
  25. export declare type ActionMatcherDescriptionCollection<S> = Array<ActionMatcherDescription<S, any>>;
  26. /**
  27. * A *case reducer* is a reducer function for a specific action type. Case
  28. * reducers can be composed to full reducers using `createReducer()`.
  29. *
  30. * Unlike a normal Redux reducer, a case reducer is never called with an
  31. * `undefined` state to determine the initial state. Instead, the initial
  32. * state is explicitly specified as an argument to `createReducer()`.
  33. *
  34. * In addition, a case reducer can choose to mutate the passed-in `state`
  35. * value directly instead of returning a new state. This does not actually
  36. * cause the store state to be mutated directly; instead, thanks to
  37. * [immer](https://github.com/mweststrate/immer), the mutations are
  38. * translated to copy operations that result in a new state.
  39. *
  40. * @public
  41. */
  42. export declare type CaseReducer<S = any, A extends Action = AnyAction> = (state: Draft<S>, action: A) => NoInfer<S> | void | Draft<NoInfer<S>>;
  43. /**
  44. * A mapping from action types to case reducers for `createReducer()`.
  45. *
  46. * @deprecated This should not be used manually - it is only used
  47. * for internal inference purposes and using it manually
  48. * would lead to type erasure.
  49. * It might be removed in the future.
  50. * @public
  51. */
  52. export declare type CaseReducers<S, AS extends Actions> = {
  53. [T in keyof AS]: AS[T] extends Action ? CaseReducer<S, AS[T]> : void;
  54. };
  55. export declare type NotFunction<T> = T extends Function ? never : T;
  56. export declare type ReducerWithInitialState<S extends NotFunction<any>> = Reducer<S> & {
  57. getInitialState: () => S;
  58. };
  59. /**
  60. * A utility function that allows defining a reducer as a mapping from action
  61. * type to *case reducer* functions that handle these action types. The
  62. * reducer's initial state is passed as the first argument.
  63. *
  64. * @remarks
  65. * The body of every case reducer is implicitly wrapped with a call to
  66. * `produce()` from the [immer](https://github.com/mweststrate/immer) library.
  67. * This means that rather than returning a new state object, you can also
  68. * mutate the passed-in state object directly; these mutations will then be
  69. * automatically and efficiently translated into copies, giving you both
  70. * convenience and immutability.
  71. *
  72. * @overloadSummary
  73. * This overload accepts a callback function that receives a `builder` object as its argument.
  74. * That builder provides `addCase`, `addMatcher` and `addDefaultCase` functions that may be
  75. * called to define what actions this reducer will handle.
  76. *
  77. * @param initialState - `State | (() => State)`: The initial state that should be used when the reducer is called the first time. This may also be a "lazy initializer" function, which should return an initial state value when called. This will be used whenever the reducer is called with `undefined` as its state value, and is primarily useful for cases like reading initial state from `localStorage`.
  78. * @param builderCallback - `(builder: Builder) => void` A callback that receives a *builder* object to define
  79. * case reducers via calls to `builder.addCase(actionCreatorOrType, reducer)`.
  80. * @example
  81. ```ts
  82. import {
  83. createAction,
  84. createReducer,
  85. AnyAction,
  86. PayloadAction,
  87. } from "@reduxjs/toolkit";
  88. const increment = createAction<number>("increment");
  89. const decrement = createAction<number>("decrement");
  90. function isActionWithNumberPayload(
  91. action: AnyAction
  92. ): action is PayloadAction<number> {
  93. return typeof action.payload === "number";
  94. }
  95. const reducer = createReducer(
  96. {
  97. counter: 0,
  98. sumOfNumberPayloads: 0,
  99. unhandledActions: 0,
  100. },
  101. (builder) => {
  102. builder
  103. .addCase(increment, (state, action) => {
  104. // action is inferred correctly here
  105. state.counter += action.payload;
  106. })
  107. // You can chain calls, or have separate `builder.addCase()` lines each time
  108. .addCase(decrement, (state, action) => {
  109. state.counter -= action.payload;
  110. })
  111. // You can apply a "matcher function" to incoming actions
  112. .addMatcher(isActionWithNumberPayload, (state, action) => {})
  113. // and provide a default case if no other handlers matched
  114. .addDefaultCase((state, action) => {});
  115. }
  116. );
  117. ```
  118. * @public
  119. */
  120. export declare function createReducer<S extends NotFunction<any>>(initialState: S | (() => S), builderCallback: (builder: ActionReducerMapBuilder<S>) => void): ReducerWithInitialState<S>;
  121. /**
  122. * A utility function that allows defining a reducer as a mapping from action
  123. * type to *case reducer* functions that handle these action types. The
  124. * reducer's initial state is passed as the first argument.
  125. *
  126. * The body of every case reducer is implicitly wrapped with a call to
  127. * `produce()` from the [immer](https://github.com/mweststrate/immer) library.
  128. * This means that rather than returning a new state object, you can also
  129. * mutate the passed-in state object directly; these mutations will then be
  130. * automatically and efficiently translated into copies, giving you both
  131. * convenience and immutability.
  132. *
  133. * @overloadSummary
  134. * This overload accepts an object where the keys are string action types, and the values
  135. * are case reducer functions to handle those action types.
  136. *
  137. * @param initialState - `State | (() => State)`: The initial state that should be used when the reducer is called the first time. This may also be a "lazy initializer" function, which should return an initial state value when called. This will be used whenever the reducer is called with `undefined` as its state value, and is primarily useful for cases like reading initial state from `localStorage`.
  138. * @param actionsMap - An object mapping from action types to _case reducers_, each of which handles one specific action type.
  139. * @param actionMatchers - An array of matcher definitions in the form `{matcher, reducer}`.
  140. * All matching reducers will be executed in order, independently if a case reducer matched or not.
  141. * @param defaultCaseReducer - A "default case" reducer that is executed if no case reducer and no matcher
  142. * reducer was executed for this action.
  143. *
  144. * @example
  145. ```js
  146. const counterReducer = createReducer(0, {
  147. increment: (state, action) => state + action.payload,
  148. decrement: (state, action) => state - action.payload
  149. })
  150. // Alternately, use a "lazy initializer" to provide the initial state
  151. // (works with either form of createReducer)
  152. const initialState = () => 0
  153. const counterReducer = createReducer(initialState, {
  154. increment: (state, action) => state + action.payload,
  155. decrement: (state, action) => state - action.payload
  156. })
  157. ```
  158. * Action creators that were generated using [`createAction`](./createAction) may be used directly as the keys here, using computed property syntax:
  159. ```js
  160. const increment = createAction('increment')
  161. const decrement = createAction('decrement')
  162. const counterReducer = createReducer(0, {
  163. [increment]: (state, action) => state + action.payload,
  164. [decrement.type]: (state, action) => state - action.payload
  165. })
  166. ```
  167. * @public
  168. */
  169. export declare function createReducer<S extends NotFunction<any>, CR extends CaseReducers<S, any> = CaseReducers<S, any>>(initialState: S | (() => S), actionsMap: CR, actionMatchers?: ActionMatcherDescriptionCollection<S>, defaultCaseReducer?: CaseReducer<S>): ReducerWithInitialState<S>;