UNPKG

redux-promise-middleware-actions

Version:

Redux action creator for making async actions with redux-promise-middleware

127 lines (117 loc) 3.37 kB
export const onPending = (type: any, delimiter = '_') => `${type}${delimiter}PENDING`; export const onFulfilled = (type: any, delimiter = '_') => `${type}${delimiter}FULFILLED`; export const onRejected = (type: any, delimiter = '_') => `${type}${delimiter}REJECTED`; export type Action< Type extends string, Payload = undefined, Meta = undefined > = Payload extends undefined ? Meta extends undefined ? { type: Type } : { type: Type; meta: Meta } : Payload extends Error ? Meta extends undefined ? { type: Type; payload: Payload; error: true } : { type: Type; payload: Payload; meta: Meta; error: true } : Meta extends undefined ? { type: Type; payload: Payload } : { type: Type; payload: Payload; meta: Meta }; export type AnyAction = Action<string>; export type ActionCreator<T extends AnyAction, U extends any[] = any> = { (...args: U): T; toString(): T['type']; }; export function createAction<Type extends string>( type: Type ): ActionCreator<Action<Type>>; export function createAction<Type extends string, Payload, U extends any[]>( type: Type, payloadCreator: (...args: U) => Payload ): ActionCreator<Action<Type, Payload>, U>; export function createAction< Type extends string, Payload, Metadata, U extends any[] >( type: Type, payloadCreator: (...args: U) => Payload, metadataCreator?: (...args: U) => Metadata ): ActionCreator<Action<Type, Payload, Metadata>, U>; /** * Standard action creator factory. * @param type Action type. * @example * const addTodo = createAction('TODO_ADD', (name) => ({ name })); */ export function createAction< Type extends string, Payload, Metadata, U extends any[] >( type: Type, payloadCreator?: (...args: U) => Payload, metadataCreator?: (...args: U) => Metadata ) { return Object.assign( (...args: U) => ({ type, ...(payloadCreator && { payload: payloadCreator(...args) }), ...(metadataCreator && { meta: metadataCreator(...args) }), }), { toString: () => type } ); } export interface AsyncActionCreator<Type extends string, Payload, Metadata> extends ActionCreator<Action<Type, Promise<Payload>, Metadata>> { pending: ActionCreator<Action<string>>; fulfilled: ActionCreator<Action<string, Payload>>; rejected: ActionCreator<Action<string, Error>>; } /** * Asynchronous action creator factory. * @param type Action type. * @example * const getTodos = createAsyncAction('TODOS_GET', () => fetch('https://todos.com/todos')); */ export function createAsyncAction< Type extends string, Payload, Metadata, U extends any[] >( type: Type, payloadCreator: (...args: U) => Promise<Payload>, metadataCreator?: (...args: U) => Metadata, { promiseTypeDelimiter: delimiter, }: { promiseTypeDelimiter?: string; } = {} ) { return Object.assign( createAction(type, payloadCreator, metadataCreator), { toString: () => { throw new Error( `Async action ${type} must be handled with pending, fulfilled or rejected` ); }, }, { pending: createAction(onPending(type, delimiter)), fulfilled: createAction( onFulfilled(type, delimiter), (payload: Payload) => payload ), rejected: createAction( onRejected(type, delimiter), (payload: Error) => payload ), } ); }