TypeScript 3.0 introduced generic rest parameters.
Up until this point, curry
functions had to be annotated in TypeScript with a finite number of function overloads and a series of conditional statements querying the number of passed arguments within the implementation.
I am hoping that generic rest parameters finally offer the mechanism needed to implement a completely generic solution.
I would like to know how to use this new language feature to write a generic curry
function... assuming it's possible of course!
The JS implementation using rest params that I modified a little from a solution I found on hackernoon looks like this:
function curry(fn) {
return (...args) => {
if (args.length === 0) {
throw new Error("Empty invocation")
} else if (args.length < fn.length) {
return curry(fn.bind(null, ...args))
} else {
return fn(...args)
}
}
}
Using generic rest params and function overloads, my attempt at annotating this curry
function in TypeScript looks like this:
interface CurriedFunction<T extends any[], R> {
(...args: T): void // Function that throws error when zero args are passed
(...args: T): CurriedFunction<T, R> // Partially applied function
(...args: T): R // Fully applied function
}
function curry<T extends any[], R>(
fn: CurriedFunction<T, R>
): CurriedFunction<T, R> {
return (...args: T) => {
if (args.length === 0) {
throw new Error("Empty invocation")
} else if (args.length < fn.length) {
return curry(fn.bind(null, ...args))
} else {
return fn(...args)
}
}
}
However TypeScript throws the error:
Type 'CurriedFunction<any[], {}>' is not assignable to type 'CurriedFunction<T, R>'.
Type '{}' is not assignable to type 'R'.
I don't understand where and why R
is being inferred as {}
?
CurriedFunction
type args is supposed to happen, sinceT
parameter toCurriedFunction
is always the same in the input and output – Lardnerany[]
to annotate the arguments of the curried function that is returned. – Denierbind()
is still not yet possible in TypeScript as of 3.0, since there's no (supported) way to concatenate tuples in the type system. So you will probably not get this done easily. – Rightful