Overloading in TypeScript - part 2

April 12, 2013 at 3:44 PMMichele Mottini

In the previous post I dealt with overloading constructors. The exact same system can be used to overload class methods - this code:

class DateHour {

  private date: Date;
  private relativeHour: number;

  . . .

  init(year: number, month: number, day: number, relativeHour: number);
  init(date: Date, relativeHour: number);
  init(dateOrYear: any, monthOrRelativeHour: number, day?: number, relativeHour?: number) {
    if (typeof dateOrYear === "number" && monthOrRelativeHour && day) {
      this.date = new Date(dateOrYear, monthOrRelativeHour, day);
      this.relativeHour = relativeHour;
    } else {
      var date = <Date> dateOrYear;
      this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
      this.relativeHour = monthOrRelativeHour;
    }
  }
}

defines an 'init' method with two overloads, one taking a year/moth/day triplet and the other a date object. The one and only implementation is hidden by the overloads, and checks the type of the parameters to determine which of the two overloads to implement.

Finally, the same system can be used to overload stand-alone functions:

function initDateHour(year: number, month: number, day: number, relativeHour: number);
function initDateHour(date: Date, relativeHour: number);
function initDateHour(dateOrYear: any, monthOrRelativeHour: number, day ? : number, relativeHour?: number) {
  if (typeof dateOrYear === "number" && monthOrRelativeHour && day) {
    // Handle the year/moth/day case    
  } else {
    // Handle the date object case
  }
}

Part 1

Posted in: Programming

Tags: ,

Overloading in TypeScript - part 1

April 8, 2013 at 6:12 PMMichele Mottini

Coming from a C#/C++ background I was baffled by the handling of overloading in TypeScript. Having to write a class that could be initialized from either a date or a year/month/day triplet I went for two overloaded constructors:

class DateHour {

  private date: Date;
  private relativeHour: number;

  constructor (year: number, month: number, day: number, relativeHour: number) {
    this.date = new Date(year, month, day);
    this.relativeHour = relativeHour;
  }

  constructor (date: Date, relativeHour: number) {
    this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
    this.relativeHour = relativeHour;
  }

}

...that does not work: TypeScript does not accept the two different constructors. The specifications do mention overloading though, so what gives?

The problem is that JavaScript does not know anything about overloading - and so TypeScript cannot generate multiple definitions of the same function differing only by their signature.

What TypeScript can do is to define multiple overloads that all map to the same function body; the class above should be defined like this:

class DateHour {

  private date: Date;
  private relativeHour: number;

  constructor(year: number, month: number, day: number, relativeHour: number);
  constructor(date: Date, relativeHour: number);
  constructor(dateOrYear: any, monthOrRelativeHour: number, day?: number, relativeHour?: number) {
    if (typeof dateOrYear === "number") {
      this.date = new Date(dateOrYear, monthOrRelativeHour, day);
      this.relativeHour = relativeHour;
    } else {
      var date = <Date> dateOrYear;
      this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
      this.relativeHour = monthOrRelativeHour;
    }
  }
}

The two overloads are still there, but as simple signature declarations, and the actual implementation of the constructor accepts a superset of the parameters of the two overloads - and determine what to do checking the type of the first parameters.

The clever bit is that in such a case the overloaded signatures hide the implementation one - auto-complete shows only two constructors: 

 and these calls are marked as invalid by the TypeScript compiler:

var start = new DateHour(2013, 0);

var current = new DateHour(new Date(), 1, 4, currentRelativeHour);

even if they match the constructor implementation. The class behaves exactly as if it had the two constructors defined in my first failed attempt.

 Part 2

 

Posted in: Programming

Tags: ,