I'm trying to define a basic function with 2 signatures to allow basic currying without including any complicated 3rd party libraries.
This is the basic function, it takes 2 arguments, if the second argument is not provided it returns a function that takes the last argument, then it will execute the function.
function concat(x, y) {
if (arguments.length === 1) {
return (_y) => concat(x, _y);
}
return x.concat(y);
}
If I use a separate index.d.ts
typescript definition file, I can use the following types.
export function concat<T>(x: T, y: T): T;
export function concat<T>(x: T): (y: T) => T;
However, if I overload the function in a ts
file I get typedef errors.
export function concat<T>(x: T, y: T): T;
export function concat<T>(x: T): (y: T) => T {
if (arguments.length === 1) {
return (_y) => concat(x, _y);
}
return x.concat(y); // Type error: TS2304: Cannot find name 'y'.
}
Is there something I am missing in the type definition inline in the ts
file?
function concat(x, y) {
if (arguments.length === 1) {
return (_y) => concat(x, _y);
}
return x.concat(y);
}
// both args provided
console.log(
concat(['one'], ['two'])
);
// curried
console.log(
concat(['one'])(['two'])
);
CodePudding user response:
You've mixed the overload declarations with the implementation. They need to be separate, regardless whether they are in the same file or not:
export function concat<T>(x: T, y: T): T;
export function concat<T>(x: T): (y: T) => T;
export function concat(x, y?) {
if (arguments.length === 1) {
return (_y) => concat(x, _y);
}
return x.concat(y);
}
CodePudding user response:
Your overload signatures are independent of the function declaration itself. Your function declaration should sport a signature that effectively "combines" the others. Here, that just means y
has to be optional (since it is required in only one of the two overloads):
export function concat<T extends { concat(other: T): T }>(x: T, y: T): T;
export function concat<T extends { concat(other: T): T }>(x: T): (y: T) => T;
export function concat<T extends { concat(other: T): T }>(x: T, y?: T) {
if (typeof y === "undefined") {
return (y: T) => concat(x, y);
}
return x.concat(y);
}
Also, you will probably noticed that I have changed arguments.length === 1
to typeof y === "undefined"
. This is just more "modern" and integrates better with TypeScript in a lot of cases (but not this one... sadly). And in the returned function, you have to add a type annotation to the y
parameter.
I have added a generic constraint as well so when you attempt to call x.concat
it no longer errors. In case you'll use this for other things that have a concat method, I chose { concat(other: T): T }
as the type.
Here is a playground, but I am unsure how well this applies to your actual use case...