JavaScript
Article

An Introduction to TypeScript: Static Typing for the Web

By Byron Houwens

This article was peer reviewed by Julian Motz and Ryan Chenkie. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

“Oh, I’m using Gulp because of reason A” or “Oh, I’m using Redux because of reason B”. You hear these sorts of things from front-end developers all the time. It’s become fashionable to use new ways of improving on JavaScript’s old faults and that’s not a bad thing; even ES2015 has been a pretty determined attempt at righting those wrongs and it’s currently the official version of the language.

One of those attempts at creating a better experience with JavaScript, which we’ll dive into here, is TypeScript. It’s a promising change to our favorite language that’s likely to make a bigger splash in JavaScript’s future.

What Exactly is TypeScript?

TypeScript is a strongly-typed superset of JavaScript, which means it adds some syntactical benefits to the language while still letting you write normal JavaScript if you want to. It encourages a more declarative style of programming through things like interfaces and static typing (more on these later), offers modules and classes, and most importantly, integrates relatively well with popular JavaScript libraries and code. You could think of it as a strongly static layer over current JavaScript that has a few features to make life (and debugging especially) a bit more bearable.

The reason it’s gained such attention of late, though, is largely because it’s been selected for full support by the upcoming Angular 2 (which is also written in TypeScript itself). It’s also developed by Microsoft, which means it has the backing of two major tech companies (not a bad place for any language). This means that we’ll probably be seeing a lot more about it in the months and years to come, and it will likely gain even more of a following and mainstream status in that time.

Needless to say, TypeScript is definitely worth looking into.

How Does it Work?

TypeScript actually looks much like modern JavaScript. At the most basic level it introduces a static typing paradigm to JavaScript, so instead of the following:

var name = “Susan”,
    age = 25,
    hasCode = true;

We could write the following:

let name: string = "Susan",
    age: number = 25,
    hasCode: boolean = true;

As you can see there’s not a whole lot of difference here. All we’re doing is explicitly telling the system what type each variable is; we’re telling it from the get-go that name is a string and age is a number. But that just seems like we have to write more code. Why bother telling the system such specific information? Because it gives the system more information about our program, which in turn means it can catch errors that we might make further down the road.

Imagine, for instance, you have something like this in your code:

var age = 25;
age = "twenty-five";

Mutating a variable like this and changing its type will likely end up breaking stuff somewhere else, especially in a really big program, so it’s great if the compiler can catch this before we load this up in our browser and have to sit for half an hour looking for the issue ourselves. Basically, it makes our program safer and more secure from bugs.

There’s more, though. Here’s an example from the TypeScript website intro tutorial (which you can find here):

interface Person {
    firstname: string;
    lastname: string;
}

function greeter(person : Person):string {
    return "Hello, " + person.firstname + " " + person.lastname;
}

let user = {firstname: "Jane", lastname: "User"};

document.body.innerHTML = greeter(user);

Now there are a few more unusual things here than we had before. We’ve got a run-of-the-mill object, called user, containing a first and last name, and that’s being passed to greeter() and the output inserted into the body of the document. But there is some bizarre looking stuff in the arguments of thegreeter function, as well as something called an interface.

Let’s start with the greeter function:

function greeter(person: Person):string {
    return "Hello, " + person.firstname + " " + person.lastname;
}

We can see that greeter takes a person parameter and we expect it to be of type Person. In this way, we can be sure that when we ask for that person’s first name, it will definitely be there and we won’t induce headaches upon ourselves if it fails. The :string after the function parameters tells us what type we expect this function to return when we call it.

The body of the function is nothing complicated but, of course, by now you’re probably wondering what on Earth a Person type actually is. This is where the interface feature comes in:

interface Person {
    firstname: string;
    lastname: string;
}

Interfaces are used in TypeScript to define the structure of objects (and only objects). In this example, we’re saying that any variable of type Person must be an object containing a firstname and a lastname property, both of the string type. We’re basically creating a custom type for our object.

This is useful because it tells the compiler, as well as yourself and any developer who will work on this in the future, exactly what type of data to expect. We’re basically modelling the object properties, creating something we can reference if we need to debug later. This is often why you’ll see interfaces at the top of TypeScript files, as they give us a good idea of the data the program is working with in the rest of the file.

In our example, if we use this Person interface with a variable at any point in the program and it doesn’t contain either a firstname or lastname, both of type string (our user object thankfully does), then the compiler will moan at us and we will be forced to mend our ways.

Not only that, but having static typing means that an IDE or editor with support for TypeScript will be able to provide us with very good, very specific hinting and auto-completion so that we can develop code that is both faster and safer.

There are many more features that TypeScript allows us to use, such as generics and namespaces, so at least a quick read of their documentation is highly recommended.

How Do I Set it Up?

Because TypeScript is a superset of JavaScript, we’ll need to transpile it into JavaScript if we want to use it in the browser. Thankfully, it integrates well with a number of task runners and bundlers already.

If you’re just looking to play around with it locally first in particular, you can install TypeScript globally via npm and use it from the command line with the tsc command, like so:

tsc your-typescript-file.ts

This will output a JavaScript file, in this case called your-typescript-file.js, which you can then use in the browser as per usual. Setting it up in a project, though, will almost certainly entail setting up a proper tsconfig.json.

This file denotes that the project is a TypeScript project, and allows us to set a number of configuration options. Here’s a truncated example from the docs:

{
    "compilerOptions": {
        "module": "commonjs",
        "outFile": "./build/local/tsc.js",
        "sourceMap": true
    },
    "exclude": [
        "node_modules"
    ]
}

Here we’re configuring the compiler in a number of ways: we’re specifying a module system to compile to, where to put the compiled file when it’s finished and to include a source map. We’re also giving it an exclude option, which basically tells the compiler to compile any TypeScript files — those ending in .ts — it finds as long as they’re not in the node_modules folder.

From here, we can integrate things into our favorite task runner or bundler. Both Grunt and Gulp have plugins for TypeScript which will expose the compiler options for your task runners, webpack has an awesome TypeScript loader and there is good support for some other setups as well. Basically, you can get TypeScript integrated into pretty much any workflow you currently have going on without too much effort.

External Typings

If you’re using external libraries in your project (let’s be honest, who isn’t?) you’ll likely also need some type definitions. These definitions — denoted by a .d.ts extension — give us access to interfaces that other people have written for a number of JavaScript libraries. By and large, these definitions are available in a gigantic repo called DefinitelyTyped, which is where we install them from.

To use them you’ll need to install Typings, which is kind of like npm but for TypeScript type definitions. It has its own config file, called typings.json, where you can configure your bundles and paths for type definition installation.

We won’t go into too much detail here, but if we wanted to use AngularJS 1.x types, for example, we could simply go typings install angularjs --save and have them downloaded into a path defined in typings.json. After that, you could use Angular’s type definitions anywhere in your project simply by including this line:

/// <reference path="angularjs/angular.d.ts" />

Now we can use Angular type definitions like the following:

var http: ng.IHttpService;

Any developers who happen upon our code at a later stage (or ourselves, three months after we’ve written it) will be able to make more sense of what we’ve written by looking at them.

Okay, What About the Community?

The TypeScript community is definitely growing quickly, as is the language’s adoption. Perhaps most importantly, it’s what AngularJS 2 is written in and the framework provides full support for it straight from the beginning. There is also fantastic support for its syntax baked into Microsoft Visual Studio IDE and Visual Studio Code, with packages and plugins for editors like Atom, Sublime Text and Emacs readily available as well.

What this means is that there’s plenty of activity going on around TypeScript and it’s likely to continue to grow, especially over the coming months and years, so this is something you’ll want to keep your eye on.

Further Reading

Conclusion

TypeScript is an interesting push toward improving on JavaScript’s shortcomings by introducing a static typing system, complete with interfaces and type unions. This helps us write safer, more legible and declarative code.

It integrates well with virtually every mainstream build setup out there at the moment and even gives us the ability to create and use custom types as well. There are also a myriad IDEs and text editors that have great support for its syntax and compile process, so you can use it in your coding environment of choice with little pain or process.

Perhaps most importantly, TypeScript is a big part of AngularJS 2 which means we’ll be seeing a lot of it both now and in the future. The more we know about it and how it works, the better equipped we’ll be to deal with it when it arrives as a fully-fledged mainstream alternative to JavaScript.

Do you feel inspired to use TypeScript in your next project? Is strong typing the future of JavaScript, or is it just a fad? Let me know what you think below!

More:
  • Tom Duncalf

    I recently wrote up in detail how to set up a new Typescript (1.9, the current beta version) + React project with Webpack and Babel, might be of interest as a lot of the steps aren’t necessarily obvious the first time round!

    http://blog.tomduncalf.com/posts/setting-up-typescript-and-react/

  • jbouzekri

    Nice article. I would have emphasized more on the fact that it is a strong typed validation at the compilation only and the compiled JS still stays loosely typed. So external data sources (like HTTP JSON API, …) could output an object not abiding by the contract defined in the TS code.

  • Pietro Grandi

    Typescript is not strongly-typed, as you can implicitly coerce unrelated types.
    ie: if (null) —> use null value in place of boolean.

  • Сергей Клевцов

    Do I understand right that TS is being transpilled into ES5 standard? If yes, what about pure ES6 then? Wouldn’t be there the situation when a developer be forced to choose one of them?

  • Сергей Клевцов

    Great! Thank you.

  • Kimberly Tran

    Nice write up, but the very first example is likely to unnecessarily scare away JS developers. TypeScript type inference is such that there’s no need to explicitly type variables to get the benefits of static type checking in many cases. You can keep writing

    var age = 25;
    age = “twenty-five”;

    and TypeScript will flag the second assignment at compile time.

    • Byron Houwens

      Agreed, but remember that the point of TypeScript is to declare, not infer. This is not code read by the machine (well it is, but only at and after compilation), it’s read by people. A bug caught by a person is better than waiting until it hits the compiler.

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in JavaScript, once a week, for free.