411

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.

Klaus Nji
  • 18,107
  • 29
  • 105
  • 185
  • 1
    Possible duplicate of [Method overloading?](https://stackoverflow.com/questions/12688275/method-overloading) – BuZZ-dEE May 02 '18 at 22:15
  • 2
    **Short answer**: method overloading to dispatch to different implementations is not possible in TS, regardless of number of params or their type(s) (`Duplicate function implementation.`). It is possible to create overloaded signatures for a single implementation, but they will all invoke the same implementation which should handle dispatching to various logic based on what it can infer from the parameters it receives. – zr0gravity7 Aug 22 '22 at 05:06

5 Answers5

358

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: string | number, b?: string) {
        alert(a.toString());
    }
}

Only the three overloads are recognized by TypeScript as possible signatures for a method call, not the actual implementation. The implementation signature must be compatible with all the overloads.

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.

Fenton
  • 241,084
  • 71
  • 387
  • 401
  • 1
    Great answer. I'd just like to highlight that, this might not be helpful when one is trying to overload for reasons such as: I would like to have an instance, where using the same constructor, I can pass an object defining all expected properties and in the one instance, pass individual params: ```class Foo { constructor(obj) { } constructor (a: number, b: string, c: boolean) {} }``` – Hlawuleka MAS Jan 05 '18 at 11:51
  • 2
    In general, I'd rather use a factory method to create me an object each way - there's no need to branch if you call `Foo.fromObject(obj)` and `Foo.fromJson(str)` and so on. – Fenton Jan 05 '18 at 15:08
  • But that postulates that one will always pass their parameters as either an object or a single string, what if I want to have them passed separately, as highlighted from my previous comment? ```Foo.methos(1, 2, 3)``` ```Foo.method(1)``` ```Foo.method(Obj)``` I also noticed you have different methods in the `Foo` Class, fromObject and fromJson? – Hlawuleka MAS Jan 06 '18 at 12:13
  • 1
    If you follow that difference back to the source, you'll usually find there is no need for it. For example, you have to type `myNum` or `myObj` anyway, so why not have separate methods and make everything clear / avoid unnecessary branching logic. – Fenton Jan 07 '18 at 15:29
  • 3
    Note that using a union type can be problematic if you want to have different return types based on the parameters. That can be solved with generics if the return type always matches one of the parameter types, but for other cases overloads are the best solution. – John Montgomery Aug 07 '18 at 17:37
  • Oh wow. I did not expect that if my implementation is `method(a: string, b?: string) {...}` I would _still_ have to define `method(a: string, b: string);` before it can be called that way. – Nyerguds Mar 21 '23 at 10:05
264

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.

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
S. Ravi Kiran
  • 4,053
  • 3
  • 21
  • 26
  • 90
    The language could be amended to support this. In theory, one could generate function implementations that are named apart and called by compiled TypeScript (e.g. createFeatureLayer_1 and createFeatureLayer_2) and createFeatureLayer could then determine which one to call based upon the contents of arguments for interoperation with vanilla JavaScript. – Thomas S. Trias May 19 '14 at 18:27
  • 11
    You word it as if overloading in TypeScript is only possible based on the number of parameters, while overloading based on type is also possible as shown in Steve Fenton's answer. – Matthijs Wessels Sep 18 '14 at 10:40
  • 23
    This is kind of lame; TypeScript should really be generating the "meta function" that chooses the uniquely named implementation appropriately based on what it was passed. How it is now there is a rift where you could pass the compiler but your implementation of the type sniffing could be incorrect. – Ezekiel Victor Feb 26 '16 at 00:37
  • 8
    @EzekielVictor TypeScript would do it if there was a reliable way of checking types at run time. – thorn0 Mar 14 '16 at 23:04
  • 5
    That's even more complicated, it's doable with JavaScript's types, but TS-specific notions like interfaces, `type`s, enums, generics, etc, are lost at runtime. That's also why you can't do `someObject instanceof ISomeInterfaceDefinedInTypeScript`. – Morgan Touverey Quilling Feb 17 '17 at 13:06
  • 4
    As per Matthijs Wessels comment - this answer is misleading and Steve Fenton's answer should be considered correct. In TypeScript overloaded functions / methods always share a single implementation that needs to handle type narrowing (i.e. determining which overload was called) at runtime.TS overloading is still useful since it type checks function use based on overload signatures, not the more general implementation signature. – user1823021 May 07 '18 at 02:24
  • 1
    without me being petty... JavaScript does have types, they are just not know at compile time. – Elior Malul Sep 01 '20 at 07:50
  • @thorn0 But TypeScript knows the types at compile type so that could be resolved at compile time. And if there's ambiguity either fail compilation or have users provide a default implementation. Doesn't seem too hard of a feature to add. – Juan Jul 05 '21 at 20:05
66

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
Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
26

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.

Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155
24

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:

Faust
  • 15,130
  • 9
  • 54
  • 111
ford04
  • 66,267
  • 20
  • 199
  • 171