It’s been known for some time that Anders Hejlsberg was doing something interesting in the JavaScript space, and when Anders is doing something interesting, it’s worth paying attention. This is, after all, the man who got Real Programmers to use Pascal, and pulled off C++++ (put two of the +’s over the other two: #! See what they did there?). Today the covers were taken off the latest project by the man himself in this Channel 9 video, and it’s TypeScript: “a strict superset of JavaScript that compiles to plain JavaScript”. What “strict superset” means is that all the valid JavaScript that already exists is also valid TypeScript; it’s like the relationship between C++ and C.

Comparisons

TypeScript sits in a similar sort of space to other languages which exist purely to be compiled to JavaScript, such as CoffeeScript, but is different in that it extends its target language instead of replacing it with an entirely different syntax. It’s even more different to cross-language compilers like Script# or ClojureScript, which take an entirely different language originally intended for an entirely different purpose and runtime, and hammer it into JavaScript submission. And it’s not a unilateral attempt to replace JavaScript like Google’s Dart, which also compiles to JS, but is primarily intended to have its own virtual machine runtime; somehow I can’t see the other browser developers implementing Dart VMs any time soon. In some ways that’s a pity, because Dart’s VM is much better than even the best JavaScript implementation, and I do agree with some of the comments that I’ve seen saying that a combined effort to implement a bytecode-based common VM across all browsers would be a better use of everybody’s time, but pragmatically speaking, that just isn’t going to happen.

A language of two halves

There are two main facets to TypeScript. Firstly, and seemingly most important to Anders, it introduces static typing as a language extension. Secondly, it provides a class-based object-oriented programming model that is more palatable to C#, C++ and Java developers than JavaScript’s own prototype-based model.

Static typing

TypeScript applies static typing using a post-fix syntax similar to that in Rust and Go. The type comes after the variable name, like this:

[sourcecode language="javascript"] function add(a: number, b: number) {
return a + b; } [/sourcecode]

That’s a little jarring if you’re used to C-style syntax, but as discussed here the post-fix annotation style works better when the “: T” is optional, which it is.

Adding static typing to a method like the above gives several benefits. It means the compiler can check all calls to the add method and ensure that they all pass numbers, and not strings, or teapots. It also means that the return type of the function can be inferred, so a call to it like this:

[sourcecode language="javascript"] var sum = add(40, 1);
[/sourcecode]

is able to statically-type the variable sum to number as well.

TypeScript also adds interfaces as a first-class language construct. These are different from classes, which are discussed below, because an object must specifically be an instance of a class, but it can simply implement one or more interfaces. An interface is declared and used like this:

[sourcecode language="javascript"] interface Rectangle {
width: number; height: number; }

function calculateArea(rectangle: Rectangle) {
return rectangle.width * rectangle.height; } [/sourcecode]

The great thing about TypeScript’s interface implementation is that it’s a structural type system: an object doesn’t need to explicitly state that it implements an interface, it just needs to match the interface’s definition. (Structural typing can be found in Go and OCaml, among other languages.) That means that the following is a valid call:

[sourcecode language="javascript"] var rect = {width: 10, height: 20};
var area = calculateArea(rect);
[/sourcecode]

The compiler is quite happy with that, because it can check that the untyped object literal in rect has the required width and height properties and they are of the correct type, so that means it implements the interface. Nice, easy and non-invasive.

Explicit type declarations and interfaces make better tooling support possible. The most obvious example is code completion (e.g. IntelliSense), which, for dynamically-typed languages, ranges from difficult to impossible to implement effectively. It’s possible to do some static code analysis and work out what some variables are going to contain at some points in the program flow, but it’s impossible to be certain what type a function argument is going to have. Giving the programmer the ability to say “element is a DOM Element” lets your editor know exactly what methods and properties are available on element, and what signatures and types those methods and properties have.

Static typing also enables more complex code-aware operations like refactoring; if a member is declared by a class or interface, and it’s possible to find all uses of that class or interface in code, then consistently renaming that member becomes possible. Of course, it’s still not going to be able to catch all cases; for example, if, in the code above, you refactored the names of the width and height properties in the Rectangle interface, the change would be applied in the calculateArea function, but not to the object literal declaration. The first you’d hear about that would be from the compiler, complaining that it didn’t match the interface declaration.

It should be noted that modern IDEs, including Visual Studio and JetBrains’ JavaScript-aware editors like WebStorm, do support both code-completion and refactoring, and they do a damn fine job of it, all things considered. But it’s far from perfect, and with TypeScript, it can be a hell of a lot better.

The other really neat trick that TypeScript’s static typing implementation can do is external type declarations. Existing JavaScript libraries can be made to appear statically-typed with a definition file, which work a lot like header files in C and C++; they just contain function signatures and interface and class declarations which match the pre-existing implementation code. At the moment, TypeScript has comprehensive type declaration files for jQuery, jQuery UI, Node.js (plus several common packages, such as Express), and WinRT and WinJS for Windows Store app development. The WinRT case is particularly interesting, because its 18,000 lines of declarations expose TypeScript-compatible information for code that isn’t even written in JavaScript. Also, in the Samples, one of the examples is an implementation of TodoMVC with Backbone.js, which includes type declarations for some of the Backbone framework and shows just how easy it is to add the information yourself if you want to.

Classy code

The second feature that TypeScript brings to the table is class-based object-oriented programming. This is a much easier approach to OOP than prototypal inheritance, particularly when declaring complex class hierarchies with inheritance and whatnot. Here’s one of my least favourite examples of a class hierarchy (my only excuse is that it’s just gone midnight and it’s been a long day):

[sourcecode language="javascript"] class Animal {
private sound: string; constructor(sound: string){ this.sound = sound; } talk() { return this.sound + "!"; } }

class Dog extends Animal {
constructor(){ super("Woof"); } } [/sourcecode]

(Incidentally, when I typed that code into the online TypeScript Playground, I actually got red squigglies telling me that the Dog constructor needed to call the super (i.e. base) constructor, which was very helpful.)

That fairly simple code compiles to this JavaScript:

[sourcecode language="javascript"] var extends = this.extends || function (d, b) {
function _() { this.constructor = d; } _.prototype = b.prototype; d.prototype = new _(); } var Animal = (function () {
function Animal(sound) { this.sound = sound; } Animal.prototype.talk = function () { return this.sound + "!"; }; return Animal; })(); var Dog = (function (
super) {
__extends(Dog, _super); function Dog() { _super.call(this, "Woof"); } return Dog; })(Animal); [/sourcecode]

Now, to be fair, that’s not idiomatic JavaScript code as it would be written by a developer, but the class-based syntax is definitely simpler. Also, the introduction of the visibility-modifier keywords like private means that any code completion can hide inaccessible members, and the compiler can enforce the visibility rules, which is just not possible in JavaScript.

It’s incredibly important to point out here that Microsoft is not, in this instance, going out by itself and randomly adding its own ideas to the language; TypeScript’s class syntax is an implementation of the class syntax proposed for ECMAScript Harmony (ES6). That’s a really big deal, because it means that when ES6 is generally available, TypeScript can simply stop compiling classes. I don’t know if the team are planning on implementing more of the ES6 proposals in this way, but I hope they are considering it.

TypeScript also includes syntactic sugar for modules, and again, this is a positive move by Microsoft. In C# and C++ code is organised into namespaces, and they could easily have brought that paradigm into TypeScript, but instead, they’ve embraced the module approach already favoured by JavaScript. In fact, TypeScript can compile modules in multiple ways, from the regular JavaScript pattern to various dynamic-loading modules such as the CommonJS Asynchronous Module Definition (AMD) system.

Things I like about TypeScript

  • I really like the fact that it’s a superset of JavaScript, that Anders and his team have extended the language rather than creating a complete replacement. It’s going to make it easier for teams to adopt the language, since it’s very readable to existing JavaScript developers. Supporting plain, undecorated JavaScript code also means that working from examples is a lot easier. And it may ameliorate the problems that CoffeeScript developers have when they post their code on Stack Overflow or elsewhere, and find that the JavaScript gurus either can’t or won’t engage with them.
  • Wherever possible, it does type inference, meaning that in a lot of places you can have plain JavaScript but the compiler and tools still know what type a variable is holding.
  • Structural typing for interfaces. I really wish C# could do that.
  • Adding a compile cycle to the development workflow gives you an extra place to catch coding mistakes, and adding static typing on top of that provides even more checking and useful compiler errors.
  • It’s open source, under the Apache 2.0 license, and they’re using Git on Codeplex so you can fork it easily.
  • It’s already self-hosting; the TypeScript compiler is written in TypeScript and compiled to JavaScript using itself (which is a sod to get to and meant somebody had to write a compiler in some other language, which then got thrown away).
  • It’s available through npm, the Node.js package manager, to be run as a command-line tool, so it works on Mac and Linux. There’s also a Visual Studio 2012 extension.
  • The class syntax complies with the ECMAScript Harmony proposal, so it should be future-proof.
  • There are packages or add-ins for Sublime Text 2, Vim and Emacs, although those only provide syntax-highlighting at present.
  • The external type declaration files mean lots of potential for TypeScript to work with the enormous range of JavaScript libraries and frameworks that are out there. I’m hoping somebody will create one for AngularJS.
  • There’s a playground where you can enter TypeScript on one side and see live-compiled JavaScript on the other.
  • There’s a good set of samples, showing TypeScript being used for browser code, Node.js server code and Windows Store apps.
  • I’m a big advocate of the JavaScript/HTML/CSS model for developing Windows Store apps, but at the moment I’m using a hybrid approach, with C# for the complex logic code. TypeScript has the potential to negate that need entirely.

Things I don’t like about TypeScript

  • I’m not entirely convinced by the full-on language support for type declaration. In the video, Anders tries to explain why they didn’t go with a comment-based system similar to those in some existing compilers, but I’m not sure I really followed it. Given that most of the other features are an ahead-of-time implementation of ECMAScript Harmony proposals, it seems like the typing is the only thing that makes TypeScript a language and not a compiler along the lines of Traceur. That said, I haven’t read the specification yet, so I might be missing something.
  • Classes can’t explicitly implement interfaces. That complaint entirely flies in the face of the previous point, but if it’s going to be a whole language, then why not push things a bit further. If classes could implement interfaces, then there’d be even more compile-time checking and refactoring could go a little further.
    My bad, classes can implement interfaces. Thanks to Guillaume Lecomte for pointing that out.
  • There’s some kind of magic going on in Visual Studio 2012 around compilation of TypeScript files, and there doesn’t seem to be a TypeScript item template in the Add New Item dialog for web or Windows Store projects.

Things I would like to see in TypeScript

  • Something like C# 5’s async/await keywords. One of the major causes of hard-to-maintain, spaghetti JavaScript is the callback pattern for asynchronous programming, and JavaScript is all about asynchronous programming. Promise-style systems like Q make life a little better, but proper syntactic sugar would be awesome.
  • Tuples and destructuring. I just like tuples and destructuring (where a tuple can be simply assigned to two or more variables in a single language construct).
  • A more complete non-Visual Studio tooling story. At the moment, only syntax highlighting is available as a plug-in for the main three text editors; some refactoring support and real-time error highlighting would also be useful. Also, packages for other IDEs like MonoDevelop, JetBrains WebStorm/PhpStorm/RubyMine, or Eclipse, will help to drive adoption. As Miguel de Icaza notes in his blog post, an awful lot of (most?) JavaScript is written by non-Windows users.
  • Source maps, so you can step-debug through the code you’ve written instead of the code the compiler has generated.
    Update:There is experimental support for source maps, if you pass --sourcemap to tcs on the command line. Hat-tip to minamo for pointing that out.