TypeScript Classes Part III

TypeScript_Tower
Welcome to this second tutorial in the series covering classes in TypeScript. The topics covered in this episode is listed below.
TypeScript Classes Part I – A New Hope (For structured JavaScript)

  1. Classes
  2. Constructors
  3. Scope Modifiers
  4. Parameter Shorthand

TypeScript Classes Part II – C# Strikes Back

  1. Accessors
  2. Static Properties

TypeScript Classes Part III – Return of the Object Hierarchy

  1. Inheritance
  2. Interfaces
  3. Abstract Classes

OBS! For version disclaimer & project setup – see the bottom of the post

Object Heirarchy

In this third episode we’re entering classical OO territory. Handling classes was, except for strong typing, the big thing that made TypeScript stand out compared to JavaScript when it was released.

Now classes are in the ES6 specs and thus coming to JavaScript, landing in a browser near you soon. But classes in JavaScript have been heavily debated in the community, and are still a divider for the passionate.

All class decisions haven’t been all uncontroversial in TypeScript either, Abstract Classes was the latest discussion point when being introduced in TypeScript 1.6.

For those of us coming from a more classic OO language before heading in to the JavaScript world, TypeScript and it’s classes can definitely be a good gateway in to actually enjoying a development environment that some developers fear, just because it’s lack of strong typing and non-straightforward OO patterns 🙂

Inheritance

Class inheritance is denoted using the extends keyword. Just mark a class with extends and then the name of the class that should be inherited.

Notable, a class can only inherit from one base class.

Example code:

class Vehicle {
	private name: string;
	private speed: number;

	constructor(name: string, speed: number) {
		this.name = name;
		this.speed = speed;
	}

	move(distance: number): string {
		var time = distance / this.speed;
		return `${this.name} moved ${distance} kilometers in ${(time * 60).toFixed(2) } minutes`;
	}
}

Now we create a class which we wish to inherit from Vehicle and we do it using the extends keyword:

class AllTerrainVehicle extends Vehicle {
	private legs: number;

	constructor(name: string, speed: number, legs: number) {
		super(name, speed);
		this.legs = legs;
	}

	move(distance: number) {
		return super.move(distance) + ` by walking on ${this.legs} legs`;
	}
}

First thing to note is that a derived class always have to call the constructor of the base class. This is can be seen on row 5 in Example 2, and is done using super.

We can see the derived class only has one private member defined, but it actually has more state, as it has the members from the base class defined as well. And not only the members from the base class but also the methods defined.
Using methods from the base class is done with calling the method name on super. This can be seen on row 10 in Example 2, where the derived class uses a method from the base class and extends it’s functionality.

Interfaces

Interfaces are used to define contracts, telling the compiler that a class is expected to implement a set of members.

In contrast to class inheritance, a class can implement several interfaces at the same time.

In TypeScript interfaces are also used heavily to define the type structure for objects we need to work with. For ex, when retrieving data from a Web API, make sure to have an interface defined for it so it’s easier to work with in TypeScript.

Defining an interface is done with the interface keyword, let’s look at some code:

interface TroopCarrier {
	troopCapacity: number;
	medicalDroid: boolean;
	pickup(troops: number): string;
}

Here we see that any class that implements this interface must define three public members, two data members and one method. Mark that the name of the interface does not start with a capital i (I) as so often seen in other languages. If you are running a TypeScript linter it will surely complain about this, but according to Microsoft’s own guidelines, this practice is to be avoided.
Declaring that a class is adhering to a contract defined in an interface is done with the implements keyword. Let’s see an example:

class AllTerrainCarrierVehicle extends Vehicle implements TroopCarrier {
	private legs: number;
	private troopsInHold: number;

	troopCapacity: number;
	medicalDroid: boolean;

	constructor(name: string, speed: number, legs: number, troopCapacity: number, hasMedicalDroid: boolean) {
		super(name, speed);
		this.legs = legs;
		this.troopCapacity = troopCapacity;
		this.medicalDroid = hasMedicalDroid;
		this.troopsInHold = 0;
	}

	move(distance: number) {
		return super.move(distance) + ` by walking on ${this.legs} legs`;
	}

	pickup(troops: number): string {
		if (this.troopsInHold + troops > this.troopCapacity) {
			return "Can't pick up that many troops";
		} else {
			this.troopsInHold += troops;
			return "Troops picked up";
		}
	}
}

Notable is that interfaces only declare member signatures, ie. it’s not possible to have an interface specify any functionality. The TroopCarrier interface can thus only specify that the pickup method needs to be implemented and how the call signature for the method is supposed to look, but it can’t define any functionality for implementing classes to use.

Abstract Classes

Much alike Interfaces are Abstract Classes. In early TypeScript this construct wasn’t in the language spec, but since TypeScript 1.6 we now have access to Abstract Classes!

An abstract class is a class that can’t be used to instantiate any objects. So in that aspect it is much like an interface. However, an abstract class can define functionality that can be used from deriving classes.

Declaring an abstract class is done using the abstract keyword. Deriving from an abstract class is done with the extends keyword, just as inheritance from regular classes. Let’s look at an example:

abstract class RepulsorliftVehicle {
	private maxSpeed: number;
	private passengers: number;
	private armaments: string;

	constructor(maxSpeed: number, passengers: number, armaments?: string) {
		this.maxSpeed = maxSpeed;
		this.passengers = passengers;
		this.armaments = armaments;
	}

	abstract pickUpPassengers(noOfPassengers: number): string;

	fire(): string {
		if (!!this.armaments) {
			return `${this.armaments} fired!`;
		} else {
			return "No armaments to fire!";
		}
	}
}

Now if we try to new up an instance of RepulsorliftVehicle it won’t work. If we’re developing in an environment that supports TypeScript, we will get a warning saying the same as the compiler will. And running the compiler will yield the message:
TS2511: Cannot create an instance of the abstract class 'RepulsorliftVehicle'.
So what kind of JavaScript sorcery is this producing to employ such trickery? Actually nothing special, it’s just tooling working for us here 🙂 If we look at the JavaScript produced it is just the same as all transpiled TypeScript classes.

Next up, inheriting from an abstract class, an example:

class SpeederBike extends RepulsorliftVehicle {
	constructor(maxSpeed: number, passengers: number, armaments: string) {
		super(maxSpeed, passengers, armaments);
	}

	pickUpPassengers(noOfPassengers: number): string {
		if (noOfPassengers > this.passengers) {
			return "Can't fit that many passengers";
		} else {
			return "Passenger get's on and holds on for dear life";
		}
	}
}

In the derived class we need to implement the methods declared as abstract in the base class, or the code won’t compile. Let’s test the SpeederBike and see what it can do:

var model74Z: SpeederBike = new SpeederBike(350, 1, "Ax-20 blaster cannon");
model74Z.pickUpPassengers(3); //returns Can't fit that many passengers
model74Z.pickUpPassengers(1); //returns Passenger get's on and holds on for dear life
model74Z.fire(); //returns Ax-20 blaster cannon fired!

Using the pickUpPassengers method that the base class had defined as abstract is done just as per usual. We also have access to the base class non abstract methods, calling fire on SpeederBike is ok.

So, that’s the strength of abstract classes demonstrated, the possibility to provide partial implementation of the behavior via the base class.

Conclusion

So this is the last part of the series detailing the workings of TypeScript classes. I hope that you have found it easy to follow along and get into the TypeScript way of handling OO. Good luck with your adventures in TypeScript and please leave a comment below, telling me how you TypeScript is workign out for you so far 🙂

Version Disclaimer & Project Setup

The code for this post was written using Visual Studio Code, ASP.NET 5 (dnvm) with runtime rc-1. Node packages TypeScript v1.7.3 and gulp-typescript v2.9.2 were used. The project was setup to compile the TypeScript files with gulp. The code was tested in Microsoft Edge.

If you want to replicate this setup, just download the code from my GitHub repository here. If you want to read more about how to setup a TypeScript project in VS Code for ASP.NET 5, read this post.

Just starting out? Developing in TypeScript

Just a quick tip if you are new to TypeScript and need help getting started. I recommend either using Visual Studio Code or Visual Studio Community Edition. Both are free and excellent development tools. Which one you should select depends on your preferences.

VS Code is more of an editor, fast and light weight, but it won’t really hold your hand during learning. Now recently launched with extension support, with many great extensions already released and the Community working hard on many more 🙂
Download Visual Studio Code.

Visual Studio is a full fledged IDE, it has pretty much everything you need to develop web, Windows applications, apps, etc. And if the functionality isn’t available out of the box, there’s a great extensibility API, enabling loads of excellent third party extensions, most of them free.
Download Visual Studio Community Edition.

More TypeScript posts for the curious

Tutorial on TypeScript Functions: TypeScript Functions

Setting up an Aurelia project in Visual Studio Code with TypeScript: Aurelia and TypeScript from VS Code

Tutorial for setting up a TypeScript – ASP.NET 5 app in VS2015: Getting started: TypeScript 1.5 in Visual Studio 2015

Tutorial for setting up a TypeScript – ASP.NET 5 app in Visual Studio Code: How-to: TypeScript in Visual Studio Code

Setup of a TypeScript – MVC 6 app that uses RequireJS in VS2015: Setting up a TypeScript – RequireJS – Gulp – MVC 6 Web Project in Visual Studio 2015 RC

Happy coding! 🙂

TypeScript Classes Part III
Tagged on:                     

4 thoughts on “TypeScript Classes Part III

Leave a Reply

Your email address will not be published. Required fields are marked *