UNPKG

typescript-fsa-redux-saga

Version:
81 lines (72 loc) 2.27 kB
import {AsyncActionCreators} from 'typescript-fsa'; import {SagaIterator} from 'redux-saga'; import {put, call, cancelled} from 'redux-saga/effects'; export interface BindAsyncActionOptions { skipStartedAction?: boolean; } export function bindAsyncAction<R>( actionCreators: AsyncActionCreators<void, R, any>, options?: BindAsyncActionOptions, ): { <Args extends any[]>( worker: (params: void, ...args: Args) => Promise<R> | SagaIterator, ): (params: void, ...args: Args) => SagaIterator; (worker: () => Promise<R> | SagaIterator): () => SagaIterator; }; export function bindAsyncAction<P, R>( actionCreators: AsyncActionCreators<P, R, any>, options?: BindAsyncActionOptions, ): { <Args extends any[]>( worker: (params: P, ...args: Args) => Promise<R> | SagaIterator, ): (params: P, ...args: Args) => SagaIterator; }; export function bindAsyncAction( actionCreator: AsyncActionCreators<any, any, any>, options: BindAsyncActionOptions = {}, ) { return ( worker: (params: any, ...args: any[]) => Promise<any> | SagaIterator, ) => { function* boundAsyncActionSaga(params: any, ...args: any[]): SagaIterator { if (!options.skipStartedAction) { yield put(actionCreator.started(params)); } try { const result = yield (call as any)(worker, params, ...args); yield put(actionCreator.done({params, result})); return result; } catch (error) { yield put(actionCreator.failed({params, error})); throw error; } finally { if (yield cancelled()) { yield put(actionCreator.failed({params, error: 'cancelled'})); } } } const capName = worker.name.charAt(0).toUpperCase() + worker.name.substring(1); return setFunctionName( boundAsyncActionSaga, `bound${capName}(${actionCreator.type})`, ); }; } /** * Set function name. * * Note that this won't have effect on built-in Chrome stack traces, although * useful for stack traces generated by `redux-saga`. */ function setFunctionName<F extends Function>(func: F, name: string): F { try { Object.defineProperty(func, 'name', { value: name, configurable: true, }); } catch (e) { // ignore } return func; }