black screen with white orange green javascript written across

Build Enterprise-Scale JavaScript Applications with TypeScript

Microsoft's TypeScript can help you create more reusable and maintainable JavaScript code

Web application technologies continue to move forward at a bristling pace -- and many of them based on HTML5 and/or JavaScript. As more and more HTML5 technologies are integrated into browsers, the amount of JavaScript that's required to support applications increases significantly. Technologies such as geolocation, local storage, canvas, web workers, WebSockets, and many others rely heavily on JavaScript. In addition to HTML5 technologies, the popularity of single-page applications, Ajax, Node.js, and other JavaScript frameworks continues to push JavaScript forward and make it increasingly more relevant to developers.

The ever-increasing usage of JavaScript code in applications makes reuse, maintainability, bugs, and other related areas crucial. This is especially true for enterprise-scale applications that could have thousands of lines of JavaScript code. Fortunately, developers have options for streamlining their JavaScript coding -- for example, by using any of several different JavaScript patterns, such as the Revealing Module Pattern and the Revealing Prototype Pattern, to structure code, and ECMAScript 6 will offer increased modularity in the future. However, ensuring that correct types (e.g., strings, numbers, Booleans) are being passed between functions can be tricky unless you add to the application robust unit tests using test frameworks such as QUnit or Jasmine. It goes without saying, though, that it would certainly be helpful to be able to structure code more easily and catch type issues up front.

To help developers who are writing "application-scale" JavaScript applications, Microsoft has released a new language called TypeScript, which addresses the aforementioned areas that can be problematic for JavaScript-based enterprise application development. Here I will introduce the fundamentals of TypeScript, describe the benefits it offers, and show how you can use TypeScript to generate JavaScript code. I'll also talk about how TypeScript can be used in several different editors, to give you code help and syntax highlighting.

Before jumping in, you should be aware that although TypeScript has several great features, it's definitely not for everyone or every project. The goal of this article isn't to convince you to use TypeScript instead of standard JavaScript. Throughout the article I'll describe different features that TypeScript offers and let you decide whether or not TypeScript is a good fit for your applications.

What Is TypeScript?

TypeScript was created by Anders Hejlsberg (the creator of the C# language) and his team at Microsoft. In a nutshell, TypeScript is a new language that can be compiled to JavaScript much like alternatives such as CoffeeScript or Dart. Here's the official definition from the TypeScript website: "TypeScript is a language for application-scale JavaScript development. TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. Any browser. Any host. Any OS. Open Source."

One of the best things about TypeScript is that it is a "superset" of JavaScript. It isn't a standalone language completely separated from JavaScript's roots. This means that you can place standard JavaScript code in a TypeScript file (a file with a .ts extension) and use it directly, which is important given all the existing JavaScript frameworks and files. Once a TypeScript file is saved, it can be compiled to JavaScript using TypeScript's tsc.exe compiler tool.

So what are some of the key features of TypeScript? First, TypeScript is built upon JavaScript, which makes it very easy for a developer to start using the language. Second, TypeScript provides built-in type support, meaning that you define variables and function parameters as being "string", "number", "bool", and others to avoid incorrect types being assigned to variables or passed to functions. Third, TypeScript provides a way to write more modular code by directly supporting class and module definitions, and it even provides support for custom interfaces. Finally, TypeScript integrates with several different tools, such as Visual Studio, Sublime Text, Emacs, and vi, to provide syntax highlighting, code help, build support, and more, depending on the editor.

Not only does TypeScript provide excellent tool support, you can also use TypeScript with existing JavaScript frameworks, such as Node.js and jQuery, and even catch type issues and provide enhanced code help. Special "declaration" files that have a d.ts extension are available for Node.js, jQuery, and other libraries out of the box. Visit the TypeScript page on CodePlex for an example of a jQuery TypeScript declaration file that can be used with tools such as Visual Studio 2012 to provide additional code help and ensure that a string isn't passed to a parameter that expects a number. Although declaration files certainly aren't required, TypeScript's support for declaration files makes it easier for you to catch problems up front while working with existing libraries such as jQuery. In the future, I expect TypeScript declaration files will be released for different HTML5 APIs, such as canvas, localStorage, and others.

Getting Started with TypeScript

One of the best ways to get started learning TypeScript is to visit the TypeScript Playground. The playground provides a way to experiment with TypeScript code, get code help as you type, and see the JavaScript that TypeScript generates once the TypeScript code is compiled. Figure 1 shows an example of the TypeScript Playground in action.

Figure 1: The TypeScript Playground
Figure 1: The TypeScript Playground

One of the first things that might stand out to you about the code shown in Figure 1 is that classes can be defined in TypeScript. This makes it easy to group related variables and functions into a container, which helps tremendously with reuse and maintainability, especially in enterprise-scale JavaScript applications. Although you can certainly simulate classes using JavaScript patterns (note that ECMAScript 6 will support classes directly), TypeScript makes the task of defining classes quite easy, especially for developers who come from an object-oriented programming background.

As an example, let's look at the Greeter class in Listing 1, which is defined using TypeScript.

class Greeter {
    greeting: string;
    constructor (message: string) {
    this.greeting = message;
    }
    greet() {
    return "Hello, " + this.greeting;
    }
}  

Looking through the code, you'll notice that static types can be defined on variables and parameters (e.g., greeting: string), that constructors can be defined, and that functions can be defined -- for example, greet(). The ability to define static types is a key feature of TypeScript (and where its name comes from) and one that can help you identify bugs before even running the code. TypeScript supports many types, including primitive types such as string, number, bool, undefined, and null, as well as object literals and more complex types such as HTMLInputElement (for an tag). Custom types can be defined as well.

The JavaScript output generated by the TypeScript class in Listing 1 is shown in Listing 2.

var Greeter = (function () {
    function Greeter(message) {
    this.greeting = message;
    }
    Greeter.prototype.greet = function () {
    return "Hello, " + this.greeting;
    };
    return Greeter;
})();

Notice in the output the use of JavaScript prototyping and closures to simulate a Greeter class in JavaScript. The body of the code is wrapped with a self-invoking function to remove the variables and functions from the global JavaScript scope. This is an important feature that helps you avoid naming collisions between variables and functions.

In cases where you'd like to wrap a class in a naming container (similar to a namespace in C# or a package in Java), you can use TypeScript's module keyword. Listing 3 shows an example of wrapping an AcmeCorp module around the Greeter class. To create a new instance of Greeter, you must now use the module name. This can help avoid naming collisions that could occur with the Greeter class.

module AcmeCorp {
    export class Greeter {
    greeting: string;
    constructor (message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
    }
}

var greeter = new AcmeCorp.Greeter("world");

In addition to defining custom classes and modules in TypeScript, you can also take advantage of inheritance by using TypeScript's extends keyword. Listing 4 shows an example of using inheritance to define two report objects.

class Report {
    name: string;
    constructor(name : string) {
    this.name = name;
     }
    print() {
    alert("Report: " + this.name);
    }
}

class FinanceReport extends Report {
    constructor(name : string) { 
    super(name); 
    }
    print() {
    alert("Finance Report: " + this.name);
    }
    getLineItems() {
    alert("5 line items");
    }
}

var report = new FinanceReport("Month's Sales")
report.print();
report.getLineItems();

In this example, a base Report class is defined that has a variable (name), a constructor that accepts a name parameter of type string, and a function named print(). The FinanceReport class inherits from Report by using TypeScript's extends keyword. As a result, the FinanceReport class automatically has access to the print() function in the base class. In this example, the FinanceReport class overrides the base class's print() method and adds its own. The FinanceReport class also forwards the name value it receives in the constructor to the base class by using the super() call.

Listing 5 shows the JavaScript code that's generated from the TypeScript code shown in Listing 4. Notice that the code includes a variable named __extends that handles the inheritance functionality in the generated JavaScript.

var __extends = this.__extends || function (d, b) {
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
}

var Report = (function () {
    function Report(name) {
    this.name = name;
    }
    Report.prototype.print = function () {
    alert("Report: " + this.name);
    };
    return Report;
})();

var FinanceReport = (function (_super) {
    __extends(FinanceReport, _super);
    function FinanceReport(name) {
    _super.call(this, name);
    }
    FinanceReport.prototype.print = function () {
    alert("Finance Report: " + this.name);
    };
    FinanceReport.prototype.getLineItems = function () {
    alert("5 line items");
    };
    return FinanceReport;
})(Report);
var report = new FinanceReport("Month's Sales");
report.print();
report.getLineItems();

TypeScript also supports the creation of custom interfaces when you need to provide consistency across a set of objects. Listing 6 shows an example of an interface named Thing (from the TypeScript samples) and a class named Plane that implements the interface to drive consistency across the app. Notice that the Plane class includes intersect and normal as a result of implementing the interface.

interface Thing {
    intersect: (ray: Ray) => Intersection;
    normal: (pos: Vector) => Vector;
    surface: Surface;
}

class Plane implements Thing {
    normal: (pos: Vector) =>Vector;
    intersect: (ray: Ray) =>Intersection;

constructor (norm: Vector, offset: number, public surface: Surface) {
    this.normal = function (pos: Vector) { return norm; }
    this.intersect = function (ray: Ray): Intersection {
        var denom = Vector.dot(norm, ray.dir);
        if (denom > 0) {
        return null;
        } else {
        var dist = (Vector.dot(norm, ray.start) + offset) / (-denom);
        return { thing: this, ray: ray, dist: dist };
        }
    }
    }
}

At first glance, it doesn't appear that the surface member is implemented in Plane, but it's actually included automatically as a result of the public surface: Surface parameter in the constructor. Adding public varName: Type to a constructor automatically adds a typed variable into the class without your having to explicitly write the code as with normal and intersect.

Although TypeScript has additional language features, defining static types and creating classes, modules, and interfaces are some of the key features it offers. Now that you've seen a few of the language features, let's look at how TypeScript can be used in editors and some of the benefits they provide.

Using TypeScript in Editors

Although you can use the TypeScript Playground to write TypeScript and generate the JavaScript code shown in the previous listings, you'll want to step up to a more robust editor at some point. This is especially true when you're building enterprise-scale JavaScript applications that involve a lot of code. Fortunately, TypeScript provides out-of-the-box support for a variety of editors -- as mentioned, Visual Studio 2012, Sublime Text, Emacs, vi, and others. To get started using TypeScript in these editors, visit the TypeScript website. By integrating TypeScript into an editor, you can get syntax highlighting, code help, and even build support (depending on the editor). Integrating TypeScript into your editor will help you more easily identify coding issues while writing code instead of after the fact.

Microsoft offers a TypeScript extension for Visual Studio 2012 that provides excellent IntelliSense and syntax highlighting to help you identify issues while you're coding -- for example, pointing out incorrect types being passed to functions. The extension also handles the task of automatically compiling .ts files to JavaScript when you save a TypeScript file, so that you don't have to use the tsc.exe command-line compiler tool. JavaScript files are automatically nested under TypeScript files, as shown in Figure 2, allowing you to access them easily and reference them from HTML, ASP.NET, or other types of web pages.

Figure 2: Generated JavaScript Files in the Visual Studio 2012 TypeScript Extension
Figure 2: Generated JavaScript Files in the Visual Studio 2012 TypeScript Extension

If you'd like to see the JavaScript that's generated as you add TypeScript code into a .ts file, download the Web Essentials extension for Visual Studio 2012. It provides a split-screen view of code with TypeScript on the left and JavaScript on the right, as shown in Figure 3. You can hide the JavaScript window when you don't want to see the generated JavaScript.

Figure 3: Viewing TypeScript and JavaScript Code Simultaneously Using the Web Essentials Extension
Figure 3: Viewing TypeScript and JavaScript Code Simultaneously Using the Web Essentials Extension

Visual Studio 2012 isn't the only game in town for TypeScript. Sublime Text has a syntax-highlighting file available as well, and you can even add a custom build system so that you can press Ctrl+B to compile a TypeScript file to JavaScript without having to resort to the command line and tsc.exe. Visit the TypeScript website to download a .zip file that contains a file named typescript.tmlanguage. Drop the file in the C:\Users\[user name]\AppData\Roaming\Sublime Text 2\Packages\User folder, and you're off and running with syntax highlighting and code help in Sublime Text.

To add a custom TypeScript build system into Sublime Text, you can perform the following steps (these steps are shown for the Windows version of Sublime Text). First, select Tools, Build System, New Build System from the Sublime Text menu. Next, copy the following code into the file that's created; then save the file.

{
    "selector": "source.ts",
    "cmd": ["tsc ", "$file"],
    "file_regex": "^(.+?) \\((\\d+),(\\d+)\\): (.+)$"
}

Once the new TypeScript build system is created, you can press Ctrl+B to compile a .ts file in Sublime Text to JavaScript.

Try Out TypeScript

This article has introduced you to some of the key features that the TypeScript language provides and showed how you can use TypeScript to write more modular JavaScript code. You've also seen how TypeScript can be used in different editors to help with syntax highlighting, to provide IntelliSense/code help, and to catch type errors more easily.

So is TypeScript right for you and your applications? You'll need to give it a spin to see what you think. If you're interested in learning more about different patterns that can be used to structure JavaScript code or more about the TypeScript language, check out the Structuring JavaScript Code and TypeScript Fundamentals courses available at Pluralsight.

Learn More About JavaScript:

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish