import pMap from 'p-map'; import { curry } from 'lodash/fp'; type AnyFunc = (...args: any) => any; /* NOTE: This type is here to enforce piped functions have the right input/output types For a list of functions it will return a new list of function but will answer the return type of the previous is the arg type of the next function */ type PipeArgs[0]> = F extends [ (arg: any) => infer B ] ? [(arg: PrevReturn) => B] : F extends [(arg: any) => infer B, ...infer Tail] ? Tail extends AnyFunc[] ? [(arg: PrevReturn) => B, ...PipeArgs] : [] : []; export function pipeAsync( ...fns: PipeArgs extends F ? F : PipeArgs ) { type Args = Parameters; type ReturnT = F extends [...AnyFunc[], (...arg: any) => infer R] ? R extends Promise ? InnerType : R : never; const [firstFn, ...fnRest] = fns; return async (...args: Args): Promise => { let res: ReturnT = await firstFn.apply(firstFn, args); for (let i = 0; i < fnRest.length; i += 1) { res = await fnRest[i](res); } return res; }; } export const mapAsync = curry(pMap); export const reduceAsync = (mixedArray: any[]) => async (iteratee: AnyFunc, initialValue?: T) => { let acc = initialValue; for (let i = 0; i < mixedArray.length; i += 1) { acc = await iteratee(acc, await mixedArray[i], i); } return acc; }; export const forEachAsync = async ( array: T[], func: pMap.Mapper, options: pMap.Options ) => { await pMap(array, func, options); };