TypeScript function overloading

Solution 1:

When you overload in TypeScript, you only have one implementation with multiple signatures.

class Foo {
    myMethod(a: string);
    myMethod(a: number);
    myMethod(a: number, b: string);
    myMethod(a: any, b?: string) {
        alert(a.toString());
    }
}

Only the three overloads are recognized by TypeScript as possible signatures for a method call, not the actual implementation.

In your case, I would personally use two methods with different names as there isn't enough commonality in the parameters, which makes it likely the method body will need to have lots of "ifs" to decide what to do.

TypeScript 1.4

As of TypeScript 1.4, you can typically remove the need for an overload using a union type. The above example can be better expressed using:

myMethod(a: string | number, b?: string) {
    alert(a.toString());
}

The type of a is "either string or number".

Solution 2:

This may be because, when both functions are compiled to JavaScript, their signature is totally identical. As JavaScript doesn't have types, we end up creating two functions taking same number of arguments. So, TypeScript restricts us from creating such functions.

TypeScript supports overloading based on number of parameters, but the steps to be followed are a bit different if we compare to OO languages. In answer to another SO question, someone explained it with a nice example: Method overloading?.

Basically, what we are doing is, we are creating just one function and a number of declarations so that TypeScript doesn't give compile errors. When this code is compiled to JavaScript, the concrete function alone will be visible. As a JavaScript function can be called by passing multiple arguments, it just works.

Solution 3:

You can declare an overloaded function by declaring the function as having a type which has multiple invocation signatures:

interface IFoo
{
    bar: {
        (s: string): number;
        (n: number): string;
    }
}

Then the following:

var foo1: IFoo = ...;

var n: number = foo1.bar('baz');     // OK
var s: string = foo1.bar(123);       // OK
var a: number[] = foo1.bar([1,2,3]); // ERROR

The actual definition of the function must be singular and perform the appropriate dispatching internally on its arguments.

For example, using a class (which could implement IFoo, but doesn't have to):

class Foo
{
    public bar(s: string): number;
    public bar(n: number): string;
    public bar(arg: any): any 
    {
        if (typeof(arg) === 'number')
            return arg.toString();
        if (typeof(arg) === 'string')
            return arg.length;
    }
}

What's interesting here is that the any form is hidden by the more specifically typed overrides.

var foo2: new Foo();

var n: number = foo2.bar('baz');     // OK
var s: string = foo2.bar(123);       // OK
var a: number[] = foo2.bar([1,2,3]); // ERROR