Ruudy
Ruudy

Reputation: 271

TypeScript method overloading

This question is about method overloading in TypeScript. I can define the interface Api without any problems. However if I implement it I get the error blow. I check which signature is called by checking the type of arg and return the right type accordingly. However the code does not compile. Unfortunately I can't find anything about overloading in the official TS docs.

interface Api {
  test(arg: string): string;
  test(arg: number): string[];
}

const api: Api = {
  test(arg: string | number) {
    if (typeof arg === "string") {
      return "string";
    }
    return ["string", "string"];
  },
};
Type '(arg: string | number) => string[] | "string"' is not assignable to type '{ (arg: string): string; (arg: number): string[]; }'.
  Type 'string[] | "string"' is not assignable to type 'string'.
    Type 'string[]' is not assignable to type 'string'.ts(2322)

Upvotes: 3

Views: 4390

Answers (2)

Elias
Elias

Reputation: 4141

If you're using classes, this works:

interface Api {
  test(arg: string): string;
  test(arg: number): string[];
}

class WhateverApi implements Api {
  test(arg: string): string;
  test(arg: number): string[];
  test(arg: string | number): string | string[] {
    throw new Error("Method not implemented.");
  }
}

It was mentioned in the comments, that this means you will need to add (and potentially expose) an extra class. Technically, you could use an anonymous class to fix that:

const api = new class implements Api {
  test(arg: string): string;
  test(arg: number): string[];
  test(arg: string | number): string | string[] {
    throw new Error("Method not implemented.");
  }
};

Upvotes: 0

Shape
Shape

Reputation: 527

Unfortunately as pointed out in the comments it is not possible to overload functions when declaring them in objects. What you can do - if you're willing to sacrifice on some convenience - is to declare your test function outside the object along with all the overload signatures and then assign it to that object.

function test(arg: string): string;
function test(arg: number): string[];
function test(arg: number|string) : string|string[] {
    if (typeof arg === "string") {
        return "string";
    }
    return ["string", "string"];
}

After the test function has been declared you can create a new object that implements the Api interface and assign your function to it.

interface Api {
    test(arg: string): string;
    test(arg: number): string[];
}

const api: Api = { test }

This is not entirely an amazing way to achieve what you want as any changes to the interface or the function declaration would also mean you'll have to change the other one as well.

There are some other answers from people way smarter than me under this question.
I know it's late, but better late than ever.

Upvotes: 2

Related Questions