[typescript] TypeScript function overloading

Section 6.3 of the TypeScript language spec talks about function overloading and gives concrete examples on how to implement this. However if I try something like this:

export class LayerFactory { 

    constructor (public styleFactory: Symbology.StyleFactory) { }

    createFeatureLayer (userContext : Model.UserContext, mapWrapperObj : MapWrapperBase) : any {           
         throw "not implemented";
    }                 

    createFeatureLayer(layerName : string, style : any) : any {
        throw "not implemented";
     }        

}

I get a compiler error indicating duplicate identifier even though function parameters are of different types. Even if I add an additional parameter to the second createFeatureLayer function, I still get a compiler error. Ideas, please.

This question is related to typescript overloading

The answer is


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

What is function overloading in general?

Function overloading or method overloading is the ability to create multiple functions of the same name with different implementations (Wikipedia)


What is function overloading in JS?

This feature is not possible in JS - the last defined function is taken in case of multiple declarations:

function foo(a1, a2) { return `${a1}, ${a2}` }
function foo(a1) { return `${a1}` } // replaces above `foo` declaration
foo(42, "foo") // "42"

... and in TS?

Overloads are a compile-time construct with no impact on the JS runtime:

function foo(s: string): string // overload #1 of foo
function foo(s: string, n: number): number // overload #2 of foo
function foo(s: string, n?: number): string | number {/* ... */} // foo implementation

A duplicate implementation error is triggered, if you use above code (safer than JS). TS chooses the first fitting overload in top-down order, so overloads are sorted from most specific to most broad.


Method overloading in TS: a more complex example

Overloaded class method types can be used in a similar way to function overloading:

class LayerFactory {
    createFeatureLayer(a1: string, a2: number): string
    createFeatureLayer(a1: number, a2: boolean, a3: string): number
    createFeatureLayer(a1: string | number, a2: number | boolean, a3?: string)
        : number | string { /*... your implementation*/ }
}

const fact = new LayerFactory()
fact.createFeatureLayer("foo", 42) // string
fact.createFeatureLayer(3, true, "bar") // number

The vastly different overloads are possible, as the function implementation is compatible to all overload signatures - enforced by the compiler.

More infos:


Function overloading in typescript:

According to Wikipedia, (and many programming books) the definition of method/function overloading is the following:

In some programming languages, function overloading or method overloading is the ability to create multiple functions of the same name with different implementations. Calls to an overloaded function will run a specific implementation of that function appropriate to the context of the call, allowing one function call to perform different tasks depending on context.

In typescript we cannot have different implementations of the same function that are called according to the number and type of arguments. This is because when TS is compiled to JS, the functions in JS have the following characteristics:

  • JavaScript function definitions do not specify data types for their parameters
  • JavaScript functions do not check the number of arguments when called

Therefore, in a strict sense, one could argue that TS function overloading doesn't exists. However, there are things you can do within your TS code that can perfectly mimick function overloading.

Here is an example:

function add(a: number, b: number, c: number): number;
function add(a: number, b: number): any;
function add(a: string, b: string): any;

function add(a: any, b: any, c?: any): any {
  if (c) {
    return a + c;
  }
  if (typeof a === 'string') {
    return `a is ${a}, b is ${b}`;
  } else {
    return a + b;
  }
}

The TS docs call this method overloading, and what we basically did is supplying multiple method signatures (descriptions of possible parameters and types) to the TS compiler. Now TS can figure out if we called our function correctly during compile time and give us an error if we called the function incorrectly.


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".


As a heads up to others, I've oberserved that at least as manifested by TypeScript compiled by WebPack for Angular 2, you quietly get overWRITTEN instead of overLOADED methods.

myComponent {
  method(): { console.info("no args"); },
  method(arg): { console.info("with arg"); }
}

Calling:

myComponent.method()

seems to execute the method with arguments, silently ignoring the no-arg version, with output:

with arg