Reputation: 1050
I am trying to create a global.d.ts
file for a vector math lib I am using. There are some functions that can take different sets of arguments. For example:
function add(x, y, returnNew) {
if (typeof x != 'number') {
returnNew = y;
if (isArray(x)) {
y = x[1];
x = x[0];
} else {
y = x.y;
x = x.x;
}
}
x += this.x;
y += this.y;
if (!returnNew) {
return this.set(x, y);
} else {
// Return a new vector if `returnNew` is truthy
return new (this.constructor)(x, y);
}
}
and the docs describe it as
add(x, y [, returnNew]) or
add(array, [, returnNew]) or
add(vec2 [, returnNew])
And it always return a vector object
How can i define such type or interface to match this behaviour?
i tried this
type addFunction = (
((x: number, y: number, returnNew?: boolean) => Vec2) |
((vec: Vec2, returnNew?: boolean) => Vec2) |
((pos: [number, number], returnNew?: boolean) => Vec2)
)
and there are no errors, but when i use it
vector.add(2, 4)
it complains Argument of type '2' is not assignable to parameter of type 'number & Vec2 & [number, number]'
What am I missing? Please note that this is a third party lib and I can write typings only and I can't touch the lib code.
Upvotes: 0
Views: 82
Reputation: 17895
Function overloading in Typescript works, but you must check what overload is used manually. So for your example...
function add(array: [number, number], returnNew?: boolean);
function add(vec2: { x: number, y: number }, returnNew?: boolean)
function add(x: number, y: number, returnNew?: boolean);
function add(
param1: [number, number] | { x: number, y: number } | number,
param2?: number | boolean,
param3?: boolean) {
if (Array.isArray(param1)) {
// overload 1
}
else if (typeof param1 === 'object') {
// overload 2
}
else {
// overload 3
}
}
Upvotes: 0
Reputation: 250376
What you defined is a union of function signatures. This is different than a function with overloads. A union of functions means that the implementing function could have any one of those signatures but not all of the. This is why when calling the arguments must be compatible with all arguments, as the argument should be valid for any one of the possible functions that could be assigned.
The syntax for a function signature with overloads is slightly different:
type addFunction = {
(x: number, y: number, returnNew?: boolean): Vec2
(vec: Vec2, returnNew?: boolean): Vec2
(pos: [number, number], returnNew?: boolean): Vec2
}
An intersection instead of a union will also act as an overloaded signature:
type addFunction = (
((x: number, y: number, returnNew?: boolean) => Vec2) &
((vec: Vec2, returnNew?: boolean) => Vec2) &
((pos: [number, number], returnNew?: boolean) => Vec2)
)
Upvotes: 2