1type Func<T extends any[], R> = (...a: T) => R 2 3/** 4 * Composes single-argument functions from right to left. The rightmost 5 * function can take multiple arguments as it provides the signature for the 6 * resulting composite function. 7 * 8 * @param funcs The functions to compose. 9 * @returns A function obtained by composing the argument functions from right 10 * to left. For example, `compose(f, g, h)` is identical to doing 11 * `(...args) => f(g(h(...args)))`. 12 */ 13export default function compose(): <R>(a: R) => R 14 15export default function compose<F extends Function>(f: F): F 16 17/* two functions */ 18export default function compose<A, T extends any[], R>( 19 f1: (a: A) => R, 20 f2: Func<T, A> 21): Func<T, R> 22 23/* three functions */ 24export default function compose<A, B, T extends any[], R>( 25 f1: (b: B) => R, 26 f2: (a: A) => B, 27 f3: Func<T, A> 28): Func<T, R> 29 30/* four functions */ 31export default function compose<A, B, C, T extends any[], R>( 32 f1: (c: C) => R, 33 f2: (b: B) => C, 34 f3: (a: A) => B, 35 f4: Func<T, A> 36): Func<T, R> 37 38/* rest */ 39export default function compose<R>( 40 f1: (a: any) => R, 41 ...funcs: Function[] 42): (...args: any[]) => R 43 44export default function compose<R>(...funcs: Function[]): (...args: any[]) => R 45 46export default function compose(...funcs: Function[]) { 47 if (funcs.length === 0) { 48 // infer the argument type so it is usable in inference down the line 49 return <T>(arg: T) => arg 50 } 51 52 if (funcs.length === 1) { 53 return funcs[0] 54 } 55 56 return funcs.reduce( 57 (a, b) => 58 (...args: any) => 59 a(b(...args)) 60 ) 61} 62