March 14, 2016

TypeScript - Function / Constructor Overloading

TypeScript supports overloading of functions/constructor, but not in the same way as in .Net. Since JavaScript does not provide support of overloading itself, TypeScript enforces strong typing against the various overload signatures at design time, the function name is the same, but the signature of each overload (i.e. their name and parameters, but not the return type) is different. But we still have to write a generalized function that could work in generated JavaScript code, that is compatible with all overloads signatures, and will have only one function implementation.

This example make it clear:

interface IShape {
        x: number;
        y: number;
        height: number;
        width: number;
    }

    class Square {
        public x: number;
        public y: number;
        public height: number;
        public width: number;

        constructor();
        constructor(obj: IShape);
        constructor(obj?: any) {
            this.x = obj && obj.x || 0
            this.y = obj && obj.y || 0
            this.height = obj && obj.height || 0
            this.width = obj && obj.width || 0;
        }
    }

Square class has total 3 constructor signatures, first one is empty, second contains an object of type implementing interface IShape, and the last overload receives parameter with type any to make it compatible with previous overloads. Also notice that only the last overload function signature could have the actual implementation code.

In the calling stack, it looks at the overload list, and check the first overload to call the function with the provided parameters. If it finds a match, it picks this overload as the correct overload. For this reason, usually overloads should be ordered from most specific to least specific.

You can create objects with this class in the following ways:

    //empty constructor
    var square1: Square;
    square1 = new Square();
    square1.x = 10;
    square1.y = 50;
    square1.height = 100;
    square1.width = 100;
    
    var squareConfig: IShape;
    squareConfig = { x: 10, y: 50, height: 100, width: 100 };

    //contstructor with interface IShap
    var square2: Square;
    square2 = new Square(squareConfig);

    //contstructor with JavaScript object literal
    var square3: Square;
    square3 = new Square({ x: 10, y: 50, height: 100, width: 100 });

If you are working in Visual Studio with TypeScript support enabled, you will get intellicense support, and display avialable overloads similar to this:

typescript-overloads-001-empty-constructor

typescript-overloads-001-IShape-constructor

Following function overloads added to the Square class, having different parameters of basic types.

 SetColor(x:boolean) : void;
 SetColor(x: number): void;
 SetColor(x: string): void;
 SetColor(x: any): void
 {
  if (typeof x == "boolean"){
   alert("Boolean overload is called, use default color value.");
  }
  else if (typeof x == "number") {
   alert("Number overload is called, use color from number value.");
  }
  else if (typeof x == "string") {
   alert("Number overload is called, use color from string value.");
  }
 }

Since we could have only one real function implementation, so inside this function body, we have to check for different types in order to respond with desired behavior.

Visual Studio Intellicense support will display overload options similar to this:

typescript-overloads-001-boolean-overload

typescript-overloads-001-number-overload

typescript-overloads-001-string-overload

Above function can be called in the following ways:

    square1.SetColor(true);
    square1.SetColor(255);
    square1.SetColor("#235253");

1 comment: