I tried to call another overloaded function within an overloaded function in typescript. Since the type Func2
is identical to the type Func1
, it is certain that the arguements passed onto func1
from func2
will be typed correctly. However, typescript seems to be unable to pick that up, and throwing an error.
type Func1 = {
(a: string, b: string): void
(a: undefined, b: undefined): void
}
const func1: Func1 = (a, b) => {
console.log(a, b)
}
type Func2 = {
(a: string, b: string): void
(a: undefined, b: undefined): void
}
const func2: Func2 = (a, b) => {
func1(a, b)
console.log(a, b)
}
/*
No overload matches this call.
Overload 1 of 2, '(a: string, b: string): void', gave the following error.
Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
Type 'undefined' is not assignable to type 'string'.
Overload 2 of 2, '(a: undefined, b: undefined): void', gave the following error.
Argument of type 'string | undefined' is not assignable to parameter of type 'undefined'.
Type 'string' is not assignable to type 'undefined'.
*/
How can I resolve this?
EDIT: Here's the actual implementation that I was attempting:
type ParseRandomArgs = {
(a: undefined, b: undefined): [number, number]
(a: number, b: undefined): [number, number]
(a: number, b: number): [number, number]
(a: [number, number], b: undefined): [number, number]
(a: [number], b: undefined): [number, number]
}
type RandomNumber = {
(a: undefined, b: undefined): number
(a: number, b: undefined): number
(a: number, b: number): number
(a: [number, number], b: undefined): number
(a: [number], b: undefined): number
}
const isNullish = (value: any) => value === undefined || value === null
const parseRandomArgs: ParseRandomArgs = (a, b) => {
if (Array.isArray(a)) {
if (a.length === 2) return a
return [0, a[0]]
}
else if (isNullish(b)) return [0, isNullish(a) ? 1 : a as number]
else return [a as number, b as number]
}
const randomFloat: RandomNumber = (a, b) => {
let [min, max] = parseRandomArgs(a, b) // [min, max]
return Math.random() * (max - min) + min
}
const randomInt: RandomNumber = (a, b) => {
let [min, max] = parseRandomArgs(a, b) // [min, max]
min = Math.ceil(min)
max = Math.floor(max)
return Math.floor(Math.random() * (max - min) + min)
}
As @Mike mentioned, making undefined
arguments optional makes overloading simpler to work out. This should work:
type RandomGenerator = {
(start: number, end?: number): number
(range: [number, number]): number;
(range: [number]): number;
}
const randomFloat: RandomGenerator = (start, end?) => {
const [min, max] = parseRandomArgs(start, end as number | undefined);
return computeRandom(min, max);
}
const randomInt: RandomGenerator = (start, end?) => {
const [min, max] = parseRandomArgs(start, end as number | undefined);
return Math.floor(computeRandom(min, max));
}
const computeRandom = (min: number, max: number): number => {
return Math.random() * (max - min) + min;
}
const parseRandomArgs = (first: number | [number, number] | [number], second: number | undefined): [number, number] => {
let args: [number, number];
if (Array.isArray(first) && first.length === 1) {
args = [0, first[0]];
} else if (Array.isArray(first) && first.length === 2) {
args = first;
} else {
args = Number.isFinite(second) ? [first, second as number] : [0, first];
}
const [min, max] = args;
return [Math.ceil(min), Math.floor(max)];
}