Channels ▼
RSS

.NET

Working with TypeScript in Visual Studio 2012


Working with Properties

TypeScript allows you to use member accessor declarations. For example, the following lines add a public Color property with the get and set member accessor that make it possible to change and retrieve the value for the underlying private color member:

//// TypeScript code
class MulticolorBadAlien extends BadAlien {
    private color: string;
    constructor(public name: string, public angle: number, public bonus: number, public rotationSpeed: number, initialColor: string) {
        super(name, angle, bonus, rotationSpeed);
        this.color = initialColor;
    }
    get Color(): string {
        return this.color;
    }

    set Country(value: string) {
        this.color = value;
    }

The TypeScript compiler generates the following JavaScript code, which calls Object.defineProperty for both the get and set accessors:

//// JavaScript code generated by the TypeScript compiler
Object.defineProperty(MulticolorBadAlien.prototype, "Color", {
    get: function () {
        return this.color;
    },
    enumerable: true,
    configurable: true
});
Object.defineProperty(MulticolorBadAlien.prototype, "Country", {
    set: function (value) {
        this.color = value;
    },
    enumerable: true,
    configurable: true
});

Working with Type Assertions

TypeScript allows you to assert a type for an expression. For example, the following createBadAlien function returns an instance of the BadAlien class. However, createBadAlien receives the desired alienType as a parameter, so it might return a new instance of the MulticolorBadAlien class (a subclass of BadAlien). Because you know that the call to createBadAlien with multicolor as the value for alienType will return an instance of MulticolorBadAlien, you can use <MulticolorBadAlien> to treat the result as a MulticoreBadAlien. It is a good idea to use the instanceof operator to check the type before using type assertions.

  //// TypeScript code
  function createBadAlien(alienType: string, name: string, angle: number, bonus: number, rotationSpeed: number, initialColor: string): BadAlien {
      if (alienType === "multicolor") {
          return new MulticolorBadAlien(name, angle, bonus, rotationSpeed, initialColor);
      }
  }
  var multicolorBadAlien = <MulticolorBadAlien> createBadAlien("multicolor", "DrDobbsMulticolorBadAlien", 0, 5000, 5, "blue");

Organizing the Code with Modules

TypeScript allows you to express the common JavaScript module pattern. You can organize your classes in modules, and decide which classes you want to be accessible from outside the module. This way, you can have internal classes within the modules that will be hidden to the module consumers.

The module keyword makes it possible to define modules with names, and the export keyword specifies which module members will be accessible from outside the module. The following lines define two modules: AliensCore and AliensCharacters. AliensCore exports the Alien interface, and AliensCharacters exports the BadAlien class that inherits from AliensCore.Alien:

//// TypeScript code
module AliensCore {
    export interface Alien {
        name: string;
        angle: number;
        bonus: number;
        rotationSpeed: number;
    }
}

module AliensCharacters {
    export class BadAlien implements AliensCore.Alien {
        private damagePower: number;

        constructor(public name: string, public angle: number, public bonus: number, public rotationSpeed: number) {
            this.damagePower = 0.1 * bonus;
        }
        increaseSpeed() { this.rotationSpeed += 1; }
    }
}

Because the interface doesn't have a representation in the JavaScript code, the TypeScript compiler only generates the code for the AliensCharacters module:

//// JavaScript code generated by the TypeScript compiler
var AliensCharacters;
(function (AliensCharacters) {
    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;
        }
        BadAlien.prototype.increaseSpeed = function () {
            this.rotationSpeed += 1;
        };
        return BadAlien;
    })();
    AliensCharacters.BadAlien = BadAlien;    
})(AliensCharacters || (AliensCharacters = {}));

Modules make it easy to organize classes, interfaces, and functions for better maintainability. You can also use nested modules by exporting the modules declared within a module.

The import keyword allows you to shorten names. For example, the following line allows you to create an alias for a long module name: SpaceGame.Core.AliensCharacters. This way, you can reference the module with the alias: SCA.

  import SCA = SpaceGame.Core.AliensCharacters;
  var firstBadAlien = new SCA.BadAlien("DrDobbsBadAlien", 0, 5000, 5);

TypeScript also supports external modules with two possible patterns of JavaScript code generation:

  • CommonJS Modules pattern: This is the default module code generation pattern. You can use --module commonjs in the command-line.
  • AMD (short for Asynchronous Module Definition): You can use --module amd in the command-line.

You can select your desired code generation pattern with a compiler setting configured in the dialog box shown in Figure 7, or with the appropriate command-line option. In TypeScript, you simply need to use the import keyword to assign an alias for the external module.

pattern selection
Figure 7: Selecting your code generation pattern.

For example, the following line will load the characters module from the characters.ts file and make it possible to reference it with the characters name.

  import characters = module("characters");
  var newCharacter = new characters.SuperBadAlien();

You can also add a dependency on a TypeScript source file by adding a comment that includes a reference path. For example, the following line adds a dependency to the TypeScript declarations to use Node.js:

  /// <reference path="node.d.ts"/>

Working with Arrow Function Expressions

An arrow function expression is a feature planned for ECMAScript 6 that makes it possible to omit the function keyword and has a lexical scoping of this. TypeScript includes support for these expressions. When you use an arrow function expression, the code preserves the this of the enclosing context, making these expression is useful for writing callbacks. The following code uses an arrow function expression to pass a parameter to the setTimeout function and access this.score:

//// TypeScript code
var game = {
    score: 0,
    startTimeout: function () {
        setTimeout(() => { alert("Your score was: " + this.score.toString()); }, 2000);
    }
};
game.startTimeout();
game.score++;
game.score++;

TypeScript generates the JavaScript code that makes the callback have the same this as the surrounding startTimeout. The following lines show how the code defines a _this variable, assigns it the value of this, and then uses _this within the callback.

//// JavaScript code generated by the TypeScript compiler 
var game = {
    score: 0,
    startTimeout: function () {
        var _this = this;
        setTimeout(function () {
            alert("Your score was: " + _this.score.toString());
        }, 2000);
    }
};
game.startTimeout();
game.score++;
game.score++;

Working with Declaration Files

If you want to work with jQuery in TypeScript with types and auto-completion, you have to reference a declaration file that includes the typing for this library. You can download the jquery.d.ts file from the TypeScript samples here. Then, you just need to add the reference path in your TypeScript file:

  /// <reference path="jquery.d.ts" />

You can also find any number of declaration files for popular JavaScript libraries in the repository for Definitely Typed. Multiple contributors generated the different declaration files and you will find declarations for popular libraries such as Backbone.js, GoogleMaps and Knockout.js.

Conclusion

TypeScript simplifies organizing and refactoring JavaScript code. It also adds value to existing JavaScript code by allowing you to take advantage of language features to reduce the number of errors and problems common with JavaScript. However, you will definitely need Visual Studio 2012 in order to take full advantage of TypeScript. If Visual Studio 2012 is your main development environment and you work with many JavaScript files in your projects, you should start taking advantage of some of its features. TypeScript is still new and there are doubtless improvements to come, but it is already a handy resource when you have large amounts of JavaScript that require better organization.


Gaston Hillar is an expert in Windows-based development and is a frequent contributor to Dr. Dobb's.

Related Article

Microsoft TypeScript: The Lay of the Land


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video