createReducer.d.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import type { Draft } from 'immer';
  2. import type { Action, Reducer, UnknownAction } from 'redux';
  3. import type { ActionReducerMapBuilder } from './mapBuilders';
  4. import type { NoInfer, TypeGuard } 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 type Actions<T extends keyof any = string> = Record<T, Action>;
  14. export type ActionMatcherDescription<S, A extends Action> = {
  15. matcher: TypeGuard<A>;
  16. reducer: CaseReducer<S, NoInfer<A>>;
  17. };
  18. export type ReadonlyActionMatcherDescriptionCollection<S> = ReadonlyArray<ActionMatcherDescription<S, any>>;
  19. export type ActionMatcherDescriptionCollection<S> = Array<ActionMatcherDescription<S, any>>;
  20. /**
  21. * A *case reducer* is a reducer function for a specific action type. Case
  22. * reducers can be composed to full reducers using `createReducer()`.
  23. *
  24. * Unlike a normal Redux reducer, a case reducer is never called with an
  25. * `undefined` state to determine the initial state. Instead, the initial
  26. * state is explicitly specified as an argument to `createReducer()`.
  27. *
  28. * In addition, a case reducer can choose to mutate the passed-in `state`
  29. * value directly instead of returning a new state. This does not actually
  30. * cause the store state to be mutated directly; instead, thanks to
  31. * [immer](https://github.com/mweststrate/immer), the mutations are
  32. * translated to copy operations that result in a new state.
  33. *
  34. * @public
  35. */
  36. export type CaseReducer<S = any, A extends Action = UnknownAction> = (state: Draft<S>, action: A) => NoInfer<S> | void | Draft<NoInfer<S>>;
  37. /**
  38. * A mapping from action types to case reducers for `createReducer()`.
  39. *
  40. * @deprecated This should not be used manually - it is only used
  41. * for internal inference purposes and using it manually
  42. * would lead to type erasure.
  43. * It might be removed in the future.
  44. * @public
  45. */
  46. export type CaseReducers<S, AS extends Actions> = {
  47. [T in keyof AS]: AS[T] extends Action ? CaseReducer<S, AS[T]> : void;
  48. };
  49. export type NotFunction<T> = T extends Function ? never : T;
  50. export type ReducerWithInitialState<S extends NotFunction<any>> = Reducer<S> & {
  51. getInitialState: () => S;
  52. };
  53. /**
  54. * A utility function that allows defining a reducer as a mapping from action
  55. * type to *case reducer* functions that handle these action types. The
  56. * reducer's initial state is passed as the first argument.
  57. *
  58. * @remarks
  59. * The body of every case reducer is implicitly wrapped with a call to
  60. * `produce()` from the [immer](https://github.com/mweststrate/immer) library.
  61. * This means that rather than returning a new state object, you can also
  62. * mutate the passed-in state object directly; these mutations will then be
  63. * automatically and efficiently translated into copies, giving you both
  64. * convenience and immutability.
  65. *
  66. * @overloadSummary
  67. * This function accepts a callback that receives a `builder` object as its argument.
  68. * That builder provides `addCase`, `addMatcher` and `addDefaultCase` functions that may be
  69. * called to define what actions this reducer will handle.
  70. *
  71. * @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`.
  72. * @param builderCallback - `(builder: Builder) => void` A callback that receives a *builder* object to define
  73. * case reducers via calls to `builder.addCase(actionCreatorOrType, reducer)`.
  74. * @example
  75. ```ts
  76. import {
  77. createAction,
  78. createReducer,
  79. UnknownAction,
  80. PayloadAction,
  81. } from "@reduxjs/toolkit";
  82. const increment = createAction<number>("increment");
  83. const decrement = createAction<number>("decrement");
  84. function isActionWithNumberPayload(
  85. action: UnknownAction
  86. ): action is PayloadAction<number> {
  87. return typeof action.payload === "number";
  88. }
  89. const reducer = createReducer(
  90. {
  91. counter: 0,
  92. sumOfNumberPayloads: 0,
  93. unhandledActions: 0,
  94. },
  95. (builder) => {
  96. builder
  97. .addCase(increment, (state, action) => {
  98. // action is inferred correctly here
  99. state.counter += action.payload;
  100. })
  101. // You can chain calls, or have separate `builder.addCase()` lines each time
  102. .addCase(decrement, (state, action) => {
  103. state.counter -= action.payload;
  104. })
  105. // You can apply a "matcher function" to incoming actions
  106. .addMatcher(isActionWithNumberPayload, (state, action) => {})
  107. // and provide a default case if no other handlers matched
  108. .addDefaultCase((state, action) => {});
  109. }
  110. );
  111. ```
  112. * @public
  113. */
  114. export declare function createReducer<S extends NotFunction<any>>(initialState: S | (() => S), mapOrBuilderCallback: (builder: ActionReducerMapBuilder<S>) => void): ReducerWithInitialState<S>;