UNPKG

@equinor/fusion-observable

Version:
92 lines (91 loc) 5.88 kB
import type { Draft } from 'immer'; import type { TypeGuard } from './types/ts-helpers'; import type { Action, ActionType, AnyAction, ExtractAction } from './types/actions'; import type { ReducerWithInitialState } from './types/reducers'; type NotFunction<T = unknown> = T extends Function ? never : T; export type ActionMatcherDescription<S, A extends AnyAction> = { matcher: TypeGuard<A> | ((action: A) => boolean); reducer: CaseReducer<S, NoInfer<A>>; }; type ActionMatcherDescriptionCollection<S> = Array<ActionMatcherDescription<S, any>>; interface TypedActionCreator<Type extends string> { (...args: any[]): Action<Type>; type: Type; } type CaseReducer<S = unknown, A extends Action = AnyAction> = (state: Draft<S>, action: A) => S | void | Draft<S>; type CaseReducers<S, AS extends Record<string, Action>> = { [T in keyof AS]: AS[T] extends Action ? CaseReducer<S, AS[T]> : void; }; /** * A utility function that allows defining a reducer as a mapping from action * type to *case reducer* functions that handle these action types. The * reducer's initial state is passed as the first argument. * * @remarks * The body of every case reducer is implicitly wrapped with a call to * `produce()` from the [immer](https://github.com/mweststrate/immer) library. * This means that rather than returning a new state object, you can also * mutate the passed-in state object directly; these mutations will then be * automatically and efficiently translated into copies, giving you both * convenience and immutability. * * @overloadSummary * This overload accepts a callback function that receives a `builder` object as its argument. * That builder provides `addCase`, `addMatcher` and `addDefaultCase` functions that may be * called to define what actions this reducer will handle. * * @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`. * @param builderCallback - `(builder: Builder) => void` A callback that receives a *builder* object to define * case reducers via calls to `builder.addCase(actionCreatorOrType, reducer)`. * * @public */ export declare function createReducer<S extends NotFunction, A extends Action = AnyAction>(initialState: S | (() => S), builderCallback: (builder: ActionReducerMapBuilder<S, A>) => void): ReducerWithInitialState<S, A>; /** * A builder for an action <-> reducer map. * * @public */ export interface ActionReducerMapBuilder<State, Actions extends AnyAction = AnyAction> { /** * Adds a case reducer to handle a single exact action type. * @remarks * All calls to `builder.addCase` must come before any calls to `builder.addMatcher` or `builder.addDefaultCase`. * @param actionCreator - Either a plain action type string, or an action creator generated by [`createAction`](./createAction) that can be used to determine the action type. * @param reducer - The actual case reducer function. */ addCase<ActionCreator extends TypedActionCreator<ActionType<Actions>>>(actionCreator: ActionCreator, reducer: CaseReducer<State, ReturnType<ActionCreator>>): ActionReducerMapBuilder<State, Actions>; /** * Adds a case reducer to handle a single exact action type. * @remarks * All calls to `builder.addCase` must come before any calls to `builder.addMatcher` or `builder.addDefaultCase`. * @param actionCreator - Either a plain action type string, or an action creator generated by [`createAction`](./createAction) that can be used to determine the action type. * @param reducer - The actual case reducer function. */ addCase<Type extends Actions['type']>(type: Type, reducer: CaseReducer<State, ExtractAction<Actions, Type>>): ActionReducerMapBuilder<State, Actions>; /** * Allows you to match your incoming actions against your own filter function instead of only the `action.type` property. * @remarks * If multiple matcher reducers match, all of them will be executed in the order * they were defined in - even if a case reducer already matched. * All calls to `builder.addMatcher` must come after any calls to `builder.addCase` and before any calls to `builder.addDefaultCase`. * @param matcher - A matcher function. In TypeScript, this should be a [type predicate](https://www.typescriptlang.org/docs/handbook/advanced-types.html#using-type-predicates) * function * @param reducer - The actual case reducer function. * */ addMatcher<TAction extends Actions = Actions>(matcher: (action: Actions) => action is TAction, reducer: CaseReducer<State, TAction extends AnyAction ? TAction : TAction & AnyAction>): Omit<ActionReducerMapBuilder<State, Actions>, 'addCase'>; addMatcher<TAction extends Actions = Actions>(matcher: (action: Actions) => boolean, reducer: CaseReducer<State, TAction extends AnyAction ? TAction : TAction & AnyAction>): Omit<ActionReducerMapBuilder<State, Actions>, 'addCase'>; /** * Adds a "default case" reducer that is executed if no case reducer and no matcher * reducer was executed for this action. * @param reducer - The fallback "default case" reducer function. */ addDefaultCase(reducer: CaseReducer<State, AnyAction>): void; } export declare function executeReducerBuilderCallback<TState, TAction extends AnyAction>(builderCallback: (builder: ActionReducerMapBuilder<TState, TAction>) => void): [ CaseReducers<TState, Record<string, TAction>>, ActionMatcherDescriptionCollection<TState>, CaseReducer<TState, TAction> | undefined ]; export {};