7

anyone know how to use method overload on arrow function?

foo(args: string): string
    foo(args: number): number
    foo(args: string | number): string | number {
        if (typeof args === "string") {
            return "string"
        }
        return 1
    }

tried this but not working

foo: {
    (args: string): string;
    (args: number): number;
} = (args: string | number): string | number => {
    if (typeof args === "string") {
      return "string"
    }
    return 1
}
Jemmy Phan
  • 73
  • 2
  • 5
  • It can actually support overloading. see https://stackoverflow.com/questions/20646171/can-i-use-typescript-overloads-when-using-fat-arrow-syntax-for-class-methods – AozakiOrenji Sep 29 '19 at 13:03
  • You can actually overloading an arrow function. see https://stackoverflow.com/questions/20646171/can-i-use-typescript-overloads-when-using-fat-arrow-syntax-for-class-methods – AozakiOrenji Sep 29 '19 at 13:05

2 Answers2

8

Arrow functions don't support overloading. From the language specification:

The descriptions of function declarations provided in chapter 6 apply to arrow functions as well, except that arrow functions do not support overloading.

When you write

foo: {
  (args: string): string;
  (args: number): number;
}

then you don't overload. You actually say that foo is a function that can take one of these forms (or rather both forms). The arrow function

(args: string | number): string | number =>

violates that restriction because it's a single function (not an overloaded one) and string | number means that you can return a number when a string is expected.

As already proposed by artem changing the return type to any or an intersection type solves the problem. But it's not the same as overloading because the compiler doesn't chose between the signatures. You effectively only have one: That of the arrow function.

dalyIsaac
  • 702
  • 8
  • 17
a better oliver
  • 26,330
  • 2
  • 58
  • 66
  • 3
    but that callable signature for `foo` works the same way as overload - when you call it with `string`, the compiler infers the return type as string, and when you call it with `number`, the return type is number. – artem Jun 08 '18 at 21:22
  • 2
    @artem Like an observer effect: If you declare it it's `string & number` but if you use it it's `string` or `number` ;) Unfortunately this construct and its implications are not explained in the specification. But yes: The effect is the same. – a better oliver Jun 12 '18 at 08:20
6

For reasons I don't fully understand, the return type of the implementation is expected to be intersection, not union:

class B {
    foo: {
        (args: string): string;
        (args: number): number;
    } = (args: string | number): string & number => {
        if (typeof args === "string") {
            return "string" as string & number;
        }
        return 1 as string & number;
    }    
}

So it's no better than just declaring the implementation to return any, as they do in documentation examples:

class B {
    foo: {
        (args: string): string;
        (args: number): number;
    } = (args: string | number): any => {
        if (typeof args === "string") {
            return "string";
        }
        return 1;
    }    
}
artem
  • 46,476
  • 8
  • 74
  • 78