Reputation: 859
I have a recursive function with 2 overloads :
export function select(
array: Float32Array,
first: number,
nth: number,
last: number,
comp: (a: number, b: number) => boolean,
): void;
export function select<T>(
array: T[],
first: number,
nth: number,
last: number,
comp: (a: T, b: T) => boolean,
): void;
export function select<T>(
array: Float32Array | T[],
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void {
// Implementation of Floyd-Rivest algorithm
// Some code
select(array, newFirst, nth, newLast, comp);
// Some code
}
Typescript complains about variable array
when calling select
function recursively in the implementation :
The argument of type 'Float32Array | T[]' is not assignable to the parameter of type '(number | T)[]'.
First, I don't really understand why typescript try to compare the type of argument array
with a type (number | T)[]
which does not exist in the different signatures. Does it try to compare the type of array
with arguments type of comp
function?
Of course I can replace the type of the argument array
by any
in the implementation signature, it works, but I would like to know if there is a better way to handle this case.
Upvotes: 0
Views: 580
Reputation: 249706
The problem is that the implementation overload (ie. the last one) is not directly callable, so when you call the function recursively the types have to be compatible with one of the two overloads, and the union is not compatible with either (typescript will not try to combine signatures to get to allow unions to be passed in)
The simplest solution in such a situation is to duplicate the implementation signature:
export function select(
array: Float32Array,
first: number,
nth: number,
last: number,
comp: (a: number, b: number) => boolean,
): void;
export function select<T>(
array: T[],
first: number,
nth: number,
last: number,
comp: (a: T, b: T) => boolean,
): void;
export function select<T>(
array: Float32Array | T[],
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void;
export function select<T>(
array: Float32Array | T[],
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void {
// Implementation of Floyd-Rivest algorithm
// Some code
let newFirst = 0
let newLast = 0
select(array, newFirst, nth, newLast, comp);
// Some code
}
Another solution would be to use a type that is more general and is applicable for both types of array, as suggested in the comments.
Upvotes: 1