UNPKG

redux-actions-promise-wrapper

Version:

Type safe wrapper for redux actions (compatible with redux-saga)

251 lines (238 loc) 6.21 kB
import { call, put as sagaPut } from 'redux-saga/effects'; import { Action, GReturnable, IIReturn, rpResolve } from './types'; /** * Automatically resolves promise of Action.promise * @param innerSaga - Generator Function for redux-saga */ const promiseHandler = <T extends string, P, R>( innerSaga: (args?: P) => IterableIterator<R> ) => function* innerFunction(action: Action<T, P, IIReturn<R>>) { try { const data: IIReturn<R> = yield call(innerSaga, action.payload); if (action.resolve) { action.resolve(data); } } catch (e) { if (action.reject) { action.reject(e); } } }; /** * Action Creator * @param type Action Type */ const actionCreator = <T, P, R>(type: T) => (payload?: P) => { let resolve: (value: IIReturn<R>) => void = () => { }; let reject: (reason?: any) => void = () => { }; const promise = new Promise<IIReturn<R>>((pResolve, pReject) => { resolve = pResolve; reject = pReject; }); return { type, payload, promise, resolve, reject }; }; export { rpResolve }; /** * Extract Actions to be used in reducer * @example * type Actions = ExtractActions<loginAction | logoutAction> */ export type ExtractActions<Base> = { [Key in keyof Base]: ActionUnion<Base[Key]> }[keyof Base]; export type ActionUnion<A> = { [Key in keyof A]: A[Key] extends (...args: any[]) => any ? ReturnType<A[Key]> extends IterableIterator<any> ? never : ReturnType<A[Key]> : never }[keyof A]; /** * Generator return value * @param t any */ export function reg<T>(t: T) { return t as GReturnable<T>; } // Helper types type invokeSignature<T extends string, P, R> = P extends undefined ? { (): Action<T, P, IIReturn<R>>; } : P extends boolean ? { (payload: boolean): Action<T, P, IIReturn<R>>; } : { (payload: P): Action<T, P, IIReturn<R>>; }; type handleAction<P, R, H> = | (P extends undefined ? () => IterableIterator<R> : (args: P) => IterableIterator<R>) | H; type actionCreator<T extends string, P, R> = P extends undefined ? () => Action<T, P, IIReturn<R>> : P extends boolean ? (payload: boolean) => Action<T, P, IIReturn<R>> : (payload: P) => Action<T, P, IIReturn<R>>; type actionHandler<T extends string, P, H, R> = H extends undefined ? undefined : (action: Action<T, P, IIReturn<R>>) => IterableIterator<any>; export function createAction<T extends string>( type: T ): { (): { (): Action<T>; TRIGGER: T; trigger: () => Action<T>; }; <P = undefined, H = undefined, R = undefined>( handleAction?: handleAction<P, R, H> ): { TRIGGER: T; trigger: actionCreator<T, P, R>; handleTrigger: actionHandler<T, P, H, R>; } & invokeSignature<T, P, R>; }; export function createAction<T extends string, ST extends string>( type: T, successType: ST ): { (): { (): Action<T>; TRIGGER: T; trigger: () => Action<T>; SUCCESS: ST; success: () => Action<ST>; }; < P = undefined, SP = undefined, H = undefined, R = undefined, SH = undefined, SR = undefined >( handleAction?: handleAction<P, R, H>, handleSuccess?: handleAction<SP, SR, SH> ): { TRIGGER: T; trigger: actionCreator<T, P, R>; handleTrigger: actionHandler<T, P, H, R>; SUCCESS: ST; success: actionCreator<ST, SP, SR>; handleSuccess: actionHandler<ST, SP, SH, SR>; } & invokeSignature<T, P, R>; }; export function createAction< T extends string, ST extends string, FT extends string >( type: T, successType: ST, failureType: FT ): { (): { (): Action<T>; TRIGGER: T; trigger: () => Action<T>; SUCCESS: ST; success: () => Action<ST>; FAILURE: FT; failure: () => Action<FT>; }; < P = undefined, SP = undefined, FP = undefined, H = undefined, R = undefined, SH = undefined, SR = undefined, FH = undefined, FR = undefined >( handleAction?: handleAction<P, R, H>, handleSuccess?: handleAction<SP, SR, SH>, handleFailure?: handleAction<FP, FR, FH> ): { TRIGGER: T; trigger: actionCreator<T, P, R>; handleTrigger: actionHandler<T, P, H, R>; SUCCESS: ST; success: actionCreator<ST, SP, SR>; handleSuccess: actionHandler<ST, SP, SH, SR>; FAILURE: FT; failure: actionCreator<FT, FP, FR>; handleFailure: actionHandler<FT, FP, FH, FR>; } & invokeSignature<T, P, R>; }; export function createAction< T extends string, ST extends string, FT extends string >(type: T, successType?: ST, failureType?: FT) { function actionPayload<P, R, SP, SR, FP, FR>( handleTrigger?: (args?: P) => IterableIterator<R>, handleSuccess?: (args?: SP) => IterableIterator<SR>, handleFailure?: (args?: FP) => IterableIterator<FR> ) { // handler return const routine = (payload?: P) => { let resolve: (value: IIReturn<R>) => void = () => { }; let reject: (reason?: any) => void = () => { }; const promise = new Promise<IIReturn<R>>((pResolve, pReject) => { resolve = pResolve; reject = pReject; }); return { type, payload, promise, resolve, reject }; }; routine.TRIGGER = type; routine.trigger = actionCreator<T, P, R>(type); if (handleTrigger) { routine.handleTrigger = promiseHandler<T, P, R>(handleTrigger); } if (successType) { routine.SUCCESS = successType; routine.success = actionCreator<ST, SP, SR>(successType); if (handleSuccess) { routine.handleSuccess = promiseHandler<ST, SP, SR>(handleSuccess); } } if (failureType) { routine.FAILURE = failureType; routine.failure = actionCreator<FT, FP, FR>(failureType); if (handleFailure) { routine.handleFailure = promiseHandler<FT, FP, FR>(handleFailure); } } return routine; } return actionPayload; } /** * transform return type of redux-saga's put to any * @param action Action */ interface Iput { test: any; } export const put = (action: Ia) => (sagaPut(action) as unknown) as Iput; interface Ia { type: string; payload?: any; [key: string]: any; }