|
| 1 | +// deno-lint-ignore no-explicit-any |
| 2 | +type AnyFunction = (...args: any[]) => any; |
| 3 | + |
| 4 | +type Curried1Function<T, P1> = { |
| 5 | + (p1: P1): T; |
| 6 | +}; |
| 7 | +type Curried2Function<T, P1, P2> = { |
| 8 | + (p1: P1): Curried1Function<T, P2>; |
| 9 | + (p1: P1, p2: P2): T; |
| 10 | +}; |
| 11 | +type Curried3Function<T, P1, P2, P3> = { |
| 12 | + (p1: P1): Curried2Function<P2, P3, T>; |
| 13 | + (p1: P1, p2: P2): Curried1Function<T, P3>; |
| 14 | + (p1: P1, p2: P2, p3: P3): T; |
| 15 | +}; |
| 16 | +type Curried4Function<T, P1, P2, P3, P4> = { |
| 17 | + (p1: P1): Curried3Function<P2, P3, P4, T>; |
| 18 | + (p1: P1, p2: P2): Curried2Function<T, P3, P2>; |
| 19 | + (p1: P1, p2: P2, p3: P3): Curried1Function<T, P4>; |
| 20 | + (p1: P1, p2: P2, p3: P3, p4: P4): T; |
| 21 | +}; |
| 22 | + |
| 23 | +/** |
| 24 | + * A function that returns a curried version of a given function |
| 25 | + * |
| 26 | + * @param {(p1: P1, p2: P2, … pn: Pn) => T} fn - The function to be curried. |
| 27 | + * @returns - A function which can be provided with only some of the arguments of the given function at each invocation, once all arguments have been provided the given function is called. |
| 28 | + * @example Usage |
| 29 | + * function add(a: number, b: number, c: number) { |
| 30 | + * return a + b + c + d; |
| 31 | + * } |
| 32 | + * |
| 33 | + * const curriedAdd = curry(add); |
| 34 | + * console.log(curriedAdd(1)(2)(3)); // 6 |
| 35 | + * console.log(curriedAdd(1, 2)(3)); // 6 |
| 36 | + * console.log(curriedAdd(1, 2, 3)); // 6 |
| 37 | + */ |
| 38 | + |
| 39 | +export function curry<T>( |
| 40 | + fn: () => T, |
| 41 | +): () => T; |
| 42 | +export function curry<T, P1>( |
| 43 | + fn: (p1: P1) => T, |
| 44 | +): (p1: P1) => T; |
| 45 | +export function curry<T, P1, P2>( |
| 46 | + fn: (p1: P1, p2: P2) => T, |
| 47 | +): Curried2Function<T, P1, P2>; |
| 48 | +export function curry<T, P1, P2, P3>( |
| 49 | + fn: (p1: P1, p2: P2, p3: P3) => T, |
| 50 | +): Curried3Function<T, P1, P2, P3>; |
| 51 | +export function curry<T, P1, P2, P3, P4>( |
| 52 | + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, |
| 53 | +): Curried4Function<T, P1, P2, P3, P4>; |
| 54 | +export function curry(fn: AnyFunction) { |
| 55 | + return function curried(...args: any[]): any { |
| 56 | + if (args.length >= fn.length) { |
| 57 | + return fn(...args); |
| 58 | + } else { |
| 59 | + return (...moreArgs: any[]) => curried(...args, ...moreArgs); |
| 60 | + } |
| 61 | + }; |
| 62 | +} |
| 63 | + |
| 64 | +function add(a: number, b: number, c: number, d: number) { |
| 65 | + return a + b + c + d; |
| 66 | +} |
| 67 | + |
| 68 | +const curriedAdd = curry(add); |
| 69 | + |
| 70 | +if (import.meta.main) { |
| 71 | + const fnn = curriedAdd(1, 2); |
| 72 | + console.log(curriedAdd(1)(2)(3)(4)); |
| 73 | + console.log(curriedAdd(1, 2)(3)(4)); |
| 74 | + console.log(curriedAdd(1, 2, 3)(4)); |
| 75 | + console.log(curriedAdd(1, 2, 3, 4)); |
| 76 | + console.log(curriedAdd(1, 2, 3, 4)); |
| 77 | +} |
0 commit comments