how to implement typescript function overload?

In order to satisfy an interface with multiple (i.e., overloaded) call signatures, a function’s implementation must be able to handle all such signatures. If fn is a Fn<number>, then you must be able to call it like this:

fn("someString"); // first overload
fn("someString", 1234); // second overload

But the implementation

function (a: string, b: number) {
  return b 
}

does not satisfy the first overload (since b would be undefined), and so is not assignable to Fn<number>.

Instead, you should consider coming up with an implementation compatible with both call signatures. For example:

let fn: Fn<number> = function (a: string, b?: number) {
  return b ?? a.length
}

Here, the implementation requires its first parameter a to be a string and takes an optional second parameter b of type number. Since b might be undefined and you have to return a number, you can’t just return b directly. In the above I return b unless it is undefined, in which case I return a.length. This is always a number and the compiler can verify the assignment as valid.


Note: there is a complication in situations where the overloaded call signatures have different return types. Unless your function expression’s implementation returns the intersection of all the return types, the compiler will not be able to verify type safety and will error, so you’ll need to use a type assertion:

interface OtherFn {
  (payload: string): string;
  (payload: string, a: number): number;
}

let fn2: OtherFn = (a: string, b?: number) => b ?? a; // error!
//  ~~~ <-- string | number not assignable to string

console.log(fn2("abc").toUpperCase()) // ABC
console.log(fn2("abc", Math.PI).toFixed(2)) // 3.14

Here you can see that fn2 does satisfy both call signatures in OtherFn, but the compiler is unable to verify it because of the different return types. You’ll need a type assertion if you want to do this with function expressions:

let fn3 = ((a: string, b?: number) => b ?? a) as OtherFn; // okay

or you can abandon function expressions and use function statements, which are checked more loosely, allowing the return type to be the union of all the call signatures return types:

function fn4(payload: string): string;
function fn4(payload: string, a: number): number;
function fn4(a: string, b?: number) {
  return b ?? a;
}

which can be seen to satisfy OtherFn despite not being manually annotated as such.

let fn5: OtherFn = fn4; // okay

Playground link to code

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top