UNPKG

@reduxjs/toolkit

Version:

The official, opinionated, batteries-included toolset for efficient Redux development

209 lines (179 loc) 6.04 kB
import { Action } from 'redux' import { IsUnknownOrNonInferrable } from './tsHelpers' /** * An action with a string type and an associated payload. This is the * type of action returned by `createAction()` action creators. * * @template P The type of the action's payload. * @template T the type used for the action type. * @template M The type of the action's meta (optional) * @template E The type of the action's error (optional) */ export type PayloadAction< P = void, T extends string = string, M = never, E = never > = WithOptional<M, E, WithPayload<P, Action<T>>> export type PrepareAction<P> = | ((...args: any[]) => { payload: P }) | ((...args: any[]) => { payload: P; meta: any }) | ((...args: any[]) => { payload: P; error: any }) | ((...args: any[]) => { payload: P; meta: any; error: any }) export type ActionCreatorWithPreparedPayload< PA extends PrepareAction<any> | void, T extends string = string > = PA extends PrepareAction<infer P> ? WithTypePropertyAndMatch< ( ...args: Parameters<PA> ) => PayloadAction<P, T, MetaOrNever<PA>, ErrorOrNever<PA>>, T, P, MetaOrNever<PA>, ErrorOrNever<PA> > : void export type ActionCreatorWithOptionalPayload< P, T extends string = string > = WithTypePropertyAndMatch< { (payload?: undefined): PayloadAction<undefined, T> <PT extends Diff<P, undefined>>(payload?: PT): PayloadAction<PT, T> }, T, P | undefined > export type ActionCreatorWithoutPayload< T extends string = string > = WithTypePropertyAndMatch<() => PayloadAction<undefined, T>, T, undefined> export type ActionCreatorWithPayload< P, T extends string = string > = WithTypePropertyAndMatch< IsUnknownOrNonInferrable< P, // TS < 3.5 infers non-inferrable types to {}, which does not take `null`. This enforces `undefined` instead. <PT extends unknown>(payload: PT) => PayloadAction<PT, T>, // default behaviour <PT extends P>(payload: PT) => PayloadAction<PT, T> >, T, P > /** * An action creator that produces actions with a `payload` attribute. */ export type PayloadActionCreator< P = void, T extends string = string, PA extends PrepareAction<P> | void = void > = IfPrepareActionMethodProvided< PA, ActionCreatorWithPreparedPayload<PA, T>, // else IfMaybeUndefined< P, ActionCreatorWithOptionalPayload<P, T>, // else IfVoid< P, ActionCreatorWithoutPayload<T>, // else ActionCreatorWithPayload<P, T> > > > /** * A utility function to create an action creator for the given action type * string. The action creator accepts a single argument, which will be included * in the action object as a field called payload. The action creator function * will also have its toString() overriden so that it returns the action type, * allowing it to be used in reducer logic that is looking for that action type. * * @param type The action type to use for created actions. * @param prepare (optional) a method that takes any number of arguments and returns { payload } or { payload, meta }. * If this is given, the resulting action creator will pass it's arguments to this method to calculate payload & meta. */ export function createAction<P = void, T extends string = string>( type: T ): PayloadActionCreator<P, T> export function createAction< PA extends PrepareAction<any>, T extends string = string >( type: T, prepareAction: PA ): PayloadActionCreator<ReturnType<PA>['payload'], T, PA> export function createAction(type: string, prepareAction?: Function) { function actionCreator(...args: any[]) { if (prepareAction) { let prepared = prepareAction(...args) if (!prepared) { throw new Error('prepareAction did not return an object') } return { type, payload: prepared.payload, ...('meta' in prepared && { meta: prepared.meta }), ...('error' in prepared && { error: prepared.error }) } } return { type, payload: args[0] } } actionCreator.toString = () => `${type}` actionCreator.type = type actionCreator.match = (action: Action<unknown>): action is PayloadAction => action.type === type return actionCreator } /** * Returns the action type of the actions created by the passed * `createAction()`-generated action creator (arbitrary action creators * are not supported). * * @param action The action creator whose action type to get. * @returns The action type used by the action creator. */ export function getType<T extends string>( actionCreator: PayloadActionCreator<any, T> ): T { return `${actionCreator}` as T } // helper types for more readable typings type Diff<T, U> = T extends U ? never : T type WithPayload<P, T> = T & { payload: P } type WithOptional<M, E, T> = T & ([M] extends [never] ? {} : { meta: M }) & ([E] extends [never] ? {} : { error: E }) type WithTypeProperty<MergeIn, T extends string> = { type: T } & MergeIn type WithMatch<MergeIn, T extends string, P, M = never, E = never> = { match(action: Action<unknown>): action is PayloadAction<P, T, M, E> } & MergeIn type WithTypePropertyAndMatch< MergeIn, T extends string, P, M = never, E = never > = WithTypeProperty<WithMatch<MergeIn, T, P, M, E>, T> type IfPrepareActionMethodProvided< PA extends PrepareAction<any> | void, True, False > = PA extends (...args: any[]) => any ? True : False type MetaOrNever<PA extends PrepareAction<any>> = ReturnType<PA> extends { meta: infer M } ? M : never type ErrorOrNever<PA extends PrepareAction<any>> = ReturnType<PA> extends { error: infer E } ? E : never type IfMaybeUndefined<P, True, False> = [undefined] extends [P] ? True : False type IfVoid<P, True, False> = [void] extends [P] ? True : False