import { UnpackPromise } from './internal/metaTypes'; type DeltaFn = (...args: UnpackPromise) => R | PromiseLike; type RiverFn = (arg: UnpackPromise) => R | PromiseLike; function pipe(): (...args: A) => UnpackPromise; function pipe(f1: DeltaFn): (...args: A) => Promise; function pipe(f1: DeltaFn, f2: RiverFn): (...args: A) => Promise; function pipe( f1: DeltaFn, f2: RiverFn, f3: RiverFn ): (...args: A) => Promise; function pipe( f1: DeltaFn, f2: RiverFn, f3: RiverFn, f4: RiverFn ): (...args: A) => Promise; function pipe( f1: DeltaFn, f2: RiverFn, f3: RiverFn, f4: RiverFn, f5: RiverFn ): (...args: A) => Promise; function pipe( f1: DeltaFn, f2: RiverFn, f3: RiverFn, f4: RiverFn, f5: RiverFn, f6: RiverFn ): (...args: A) => Promise; function pipe( f1: DeltaFn, f2: RiverFn, f3: RiverFn, f4: RiverFn, f5: RiverFn, f6: RiverFn, f7: RiverFn ): (...args: A) => Promise; function pipe( f1: DeltaFn, f2: RiverFn, f3: RiverFn, f4: RiverFn, f5: RiverFn, f6: RiverFn, f7: RiverFn, f8: RiverFn ): (...args: A) => Promise; function pipe( f1: DeltaFn, f2: RiverFn, f3: RiverFn, f4: RiverFn, f5: RiverFn, f6: RiverFn, f7: RiverFn, f8: RiverFn, f9: RiverFn ): (...args: A) => Promise; function pipe( f1: DeltaFn, f2: RiverFn, f3: RiverFn, f4: RiverFn, f5: RiverFn, f6: RiverFn, f7: RiverFn, f8: RiverFn, f9: RiverFn, f10: RiverFn ): (...args: A) => Promise; function pipe(deltaFn: DeltaFn, ...riverFns: Array>): (...args: any) => Promise; /** * Create a function composed of provided functions in left-to-right execution chain. * Resulting function arguments are identical to the arguments of the first function * and return value identical to the result value of the last function in the chain. * ```typescript * const myPipe = pipe( * (x: string) => x + 'first ', * (x: string) => x + 'second', * ); * await myPipe('Called: ') // 'Called: first second' * ``` * First function can have multiple arguments: * ```typescript * await pipe( * (a: number, b: number) => a + b, * String, * )(1, 2); // '3' * ``` * In-between the steps, all result promises are resolved. If result is an array, elements are resolved via Promise.all * ```typescript * await pipe( * // first function has 0 args, resulting pipe has 0 args * // any function can return promise, next function receives value as arg * () => Promise.resolve([1, 2, 5, 8]) * // returning array of promises * // no need to wrap in promise resolved * (ids: number[]) => ids.map(db.find), * // resolved array of users ready in next function * (users: User[]), => users.map(countUserRating), * )(); // userRating[] * ``` * @return Function with signature of the first function (or no args if no functions provided) returning Promise of a result of last function */ function pipe(...fns: any[]): any { return (...initialArgs: any[]) => fns.reduce( (pendingLastResult, fn, i) => pendingLastResult.then((lastResult: any) => { // first iteration (lastResult is initialArgs), spread into delta function const currentResult = i === 0 ? fn(...lastResult) : fn(lastResult); return Array.isArray(currentResult) ? Promise.all(currentResult) : currentResult; }), Promise.all(initialArgs) ); } export default pipe;