Home > Net >  How to implement method overload in TypeScript on a plain object?
How to implement method overload in TypeScript on a plain object?

Time:12-22

Given this code:

type Foo = {
  func(a:string):void;
  func(b:number, a:string):void;
}

const f:Foo = {
  func(b, a) {
    // ???
  }
}

I get the error

Type '(b: number, a: string) => void' is not assignable to type '{ (a: string): void; (b: number, a: string): void; }'.ts(2322) index.ts(15, 3): The expected type comes from property 'func' which is declared here on type 'Foo'

I see answers using classes, but how to implement on plain objects?

CodePudding user response:

The compiler is apparently unhappy that func(b, a) requires a second argument while the func method of Foo does not. You can get rid of the error by making a optional in the implementation:

const f: Foo = {
  func(b, a?) {    
  //       ^-- optional
  }
}

Note that in general it's not always possible to find a way to do this that will compile. Overloaded function statements allow their implementation to be more loosely typed than any of the call signatures, but overloaded function expressions don't work that way:

function barFunc(a: string): number;
function barFunc(b: number, a: string): string;
function barFunc(b: string | number, a?: string) {
  return typeof b === "string" ? b.length : a // okay
}

type Bar = {
  func(a: string): number;
  func(b: number, a: string): string;
}
const g: Bar = {
  func(b, a?) { // error!
    return typeof b === "string" ? b.length : a
  }
}

There's a feature request at microsoft/TypeScript#47669 to allow for arrow functions to be overloaded the same way that function statements are, but for now it's not part of the language.

So if you do find yourself with an impossible-to-implement overloaded arrow function, you should either refactor to a function statement:

const h: Bar = { func: barFunc }; // okay

Or use type assertions to loosen the type checking enough to get it to compile:

const i: Bar = {
  func(b, a?) { 
    return (typeof b === "string" ? b.length : a) as any // okay
  }
}

Playground link to code

  • Related