When you initialize variables or call functions to assign values to variables, you won't need to add explicit types because the type inference mechanism will generate the type information for both the TypeScript language service in the code editor and the compiler. Thus, you can detect errors related to types without having to use explicitly typed variables everywhere. For example, consider the following explicitly typed variable declaration:
var url: string = "www.drdobbs.com";
It isn't necessary to use the explicitly string
typed variable declaration in order to enable type checking for TypeScript. TypeScript will know that the url
variable is a string
with just the following line:
var url = "www.drdobbs.com";
TypeScript allows you to easily specify optional parameters with default values. The following simple TypeScript code adds an optional fractionDigits
parameter to the calculateCircleArea
function by adding a question mark (?
) to the parameter name. Notice that the default value for fractionDigits
is 2
. Thus, there is no need to explicitly specify the number
type because TypeScript will infer it (Figure 6):
//// TypeScript code function calculateCircleArea(radius: number, fractionDigits? = 2) { return (Math.PI * Math.pow(radius, 2)).toFixed(fractionDigits); }
Figure 6: The TypeScript editor displaying a tooltip with the parameters and types for the calculateCircleArea function.
The following lines show the JavaScript code that the TypeScript compiler generates:
//// JavaScript code generated by the TypeScript compiler function calculateCircleArea(radius, fractionDigits) { if (typeof fractionDigits === "undefined") { fractionDigits = 2; } return (Math.PI * Math.pow(radius, 2)).toFixed(fractionDigits); } alert(calculateCircleArea(10).toString());
In this case, the TypeScript compiler added the necessary JavaScript lines to check whether the type of fractionDigits
is undefined
. If the type is undefined, the code sets the default value of 2
to fractionDigits
. This way, the call to the calculateCircleArea
function with just the radius
parameter specified works without problems and is a valid call. The syntax in TypeScript to define an optional parameter is easier to read than the JavaScript lines. In addition, TypeScript supports the object types, which will be further explored in a future article.
Interfaces
TypeScript supports interfaces as compile-time constructs that don't have a runtime representation; that is, they don't generate JavaScript code. You can use interfaces to declare a new named object-type and validate that required objects are passed as parameters and returned from functions.
Suppose you're developing a game that has aliens as the main characters. The following simple TypeScript code defines an Alien
interface with the desired types for name
, angle
, bonus
and rotationSpeed
. The introduceAlien
function receives an Alien
and uses both its name
and bonus
to display a message:
//// TypeScript code interface Alien { name: string; angle: number; bonus: number; rotationSpeed: number; } function introduceAlien(alien: Alien) { return "I am " + alien.name + " and my bonus is " + alien.bonus.toString() + "."; } alert(introduceAlien({ name: "DrDobbsAlien", angle: 0, bonus: 5000, rotationSpeed: 5 }));
The following lines show the JavaScript code that the TypeScript compiler generates from this simple code. Notice that the interface doesn't generate JavaScript, so you just have the lines that define the introduceAlien
function and the code that calls it:
//// JavaScript code generated by the TypeScript compiler function introduceAlien(alien) { return "I am " + alien.name + " and my bonus is " + alien.bonus.toString() + "."; } alert(introduceAlien({ name: "DrDobbsAlien", angle: 0, bonus: 5000, rotationSpeed: 5 }));
Now, if you were to enter alert(introduceAlien({
and then press Ctrl + Space, the TypeScript editor would display a context menu with the four fields of the Alien
interface (see Figure 7) because the editor knows that introduceAlien
requires an Alien
as defined in the interface. Thus, the interface enables you to reduce the number of runtime errors when functions require or return objects with certain fields.
Figure 7: The TypeScript editor displaying a context menu with the four fields of the Alien interface.
TypeScript supports classes and inheritance, which allows you to create derived classes that specialize base classes. When you define classes, the TypeScript compiler generates JavaScript code for them, but the member's accessibility disappears in JavaScript, as you will see in this example. TypeScript enforces private accessibility at compile-time, but there is no code that defines members as private at runtime. The following TypeScript code defines a BadAlien
class that implements the previously introduced Alien
interface. The code uses the previously shown introduceAlien
function, which requires an Alien
and, in this case, receives a BadAlien
instance:
//// TypeScript code class BadAlien implements Alien { damagePower: number; constructor(public name: string, public angle: number, public bonus: number, public rotationSpeed: number) { this.damagePower = 0.1 * bonus; } } interface Alien { name: string; angle: number; bonus: number; rotationSpeed: number; } function introduceAlien(alien: Alien) { return "I am " + alien.name + " and my bonus is " + alien.bonus.toString() + "."; } var firstBadAlien = new BadAlien("DrDobbsBadAlien", 0, 5000, 5); alert(introduceAlien(firstBadAlien));
The following lines show the JavaScript code that the TypeScript compiler generates. Notice how the BadAlien
class and its constructor are translated to functions:
//// JavaScript code generated by the TypeScript compiler var BadAlien = (function () { function BadAlien(name, angle, bonus, rotationSpeed) { this.name = name; this.angle = angle; this.bonus = bonus; this.rotationSpeed = rotationSpeed; this.damagePower = 0.1 * bonus; } return BadAlien; })(); function introduceAlien(alien) { return "I am " + alien.name + " and my bonus is " + alien.bonus.toString() + "."; } var firstBadAlien = new BadAlien("DrDobbsBadAlien", 0, 5000, 5); alert(introduceAlien(firstBadAlien));
Conclusion
In this article, I've explained the main benefits and features of TypeScript, and provided a brief overview of types, interfaces, and classes, focusing on the TypeScript Playground and the IntelliSense features that also work with Visual Studio 2012. In the next article in this series, I'll explain how you can work with TypeScript in Visual Studio 2012 with the latest versions of the plug-in and the compiler. In addition, I'll dive deeper into the support for classes, inheritance, properties, member accessibility, type assertions, arrow function expressions, modules, and automatically generated declarations that allow you to use all of TypeScript's handy features when consuming the most common JavaScript libraries.
Gaston Hillar is an expert in Windows-based development and is a frequent contributor to Dr. Dobb's.