In TypeScript, I am attempting to define types for a currying function. The implementation in JavaScript is shown below:
function curry1(fn) {
return (x) => (fn.length === 1 ? fn(x) : curry1(fn.bind(undefined, x)));
}
This function works effectively by producing a unary function when applied with curry1
. Subsequent calls with arguments will result in more unary functions until all parameters are provided, ultimately producing a final result. Currying f1
generates a function equivalent to (a)=>(b)=>(c)=>result
.
const make3 = (a, b, c) => `${a}:${b}:${c}`;
const f1 = curry1(make3);
const f2 = f1('A');
const f3 = f2(2);
const f4 = f3('Z');
console.log(f4); // A:2:Z
I have created a generic type CURRY1
that either produces a result or a curried function based on the number of arguments provided.
type CURRY1<P extends any[], R> = P extends [infer H]
? (arg: H) => R // only 1 arg?
: P extends [infer H0, infer H1, ...infer T] // 2 or more args?
? (arg: H0) => CURRY1<[H1, ...T], R>
: never;
Then, I implemented the actual currying function like so:
function curry1<P extends any[], R>(fn: (...args: P) => R): CURRY1<P, R> {
return (x: any): any => (fn.length === 1 ? fn(x) : curry1(fn.bind(undefined, x)));
}
When defining a sample function and applying curry1
, the correct type inference is displayed by VSCode. However, TypeScript throws an error stating
Type '(x: any) => any' is not assignable to type 'CURRY1<P, R>' ts(2322)
. Using // @ts-ignore
before return
resolves the issue, but I am seeking a cleaner solution to avoid this error. Any suggestions?