Just another Adobe Blogs site

Kicking TypeScript’s Tires

When Microsoft introduced TypeScript – a language for large-scale web application development – at the begin of this month I noticed something strange. Similar to the process of buying a car I started by asking myself questions like: “Does it do this, or that?”, “Can I use it for that?”. But my questions were not random at all. Instead it seemed that my intuition, which guides my curiosity about languages that cross-compile to JavaScript, must use a secret checklist. In this post I will try to verbalize that checklist. Frankly, I want to know myself: What do I find important about a higher level language for developing large-scale web applications?

The Water in Aarhus

One day after Microsoft announced TypeScript, Google’s Dart team posted a warm welcome note. They pointed out that there must be something special about the location of Aarhus in Denmark in regards to languages for large-scale web application development:

It must be something in the water. Gilad Bracha and Lars Bak announced Dart in Aarhus, Denmark about a year ago as a “new programming language for structured web programming”. Yesterday, Anders Hejlsberg, once again in Aarhus, Denmark, announced Microsoft’s new programming language, TypeScript, “a language for application-scale JavaScript development”. Obviously, there’s something about the water in Aarhus that causes language designers to want to tackle the problem of large scale web development.

Google’s Dart team concludes that Dart and TypeScript clearly have the same long-term goals:

A year ago, JavaScript programmers would frequently ask us why we needed a new programming language for the web. We argued that developing large web applications was hard, and that optional static type annotations could help. We also argued that the web needed better tooling support. We think that TypeScript has validated both of these statements. Going forward, I think the Dart project and TypeScript will learn a lot from each other.

Let’s walk over to our neighbor’s house with some pie and welcome them. I would like to get to know TypeScript better!

Does TypeScript have a language spec?

That was actually my first question: Does TypeScript have a language specification? Now, let me reiterate that a language specification is not a tutorial, FAQ, or online help about that language. A good language specification is so detailed that it can be used to implement a compiler. Most language specifications have more in common with insurance policies and the legal fine print of credit card applications. I am one of those weirdos that love reading them. But that’s probably, because I work in the kitchen while others enjoy eating dinner without having to worry about the details of preparing a meal.

Good news is, that TypeScript does have a language specification and it is actually readable and not as dry as Dart’s. What conclusions do I draw from the fact that there is a language spec for TypeScript? It tells me that I am dealing with professionals that are serious about language design. Sadly, Adobe has missed to provide a language specification for ActionScript and for that reason never really made the list of what I consider well-designed programming languages.

Does TypeScript support types?

Yes, TypeScript does support types! Like in Dart type annotations are optional. That means at least you can write clean code that is fully typed if you want to. But how about those sneaky types that are not really types, like Object, “*”, or Array? In a perfect world I would not allow any of those. I am in particular interested in Array, because Arrays turn everything you put into them into untyped Objects. In ActionScript Vectors are therefore a better choice.

First I thought TypeScript didn’t support typed arrays, or vectors. But I was wrong. I wrote up this language spec request, and the friendly folks at Microsoft pointed out that typed arrays are already support in TypeScript:

var arr : number[] = [];

I clearly overlooked that when I was reading the TypeScript language spec.

Does TypeScript allow explicit casts?

I know, casting is a bad thing but sometimes you have to deal with code that wants to cast a bunny to a toaster, or vice versa. In order to cast safely your code has to be able to determine what the instance is made of (with something like ‘instanceof’ or ‘is’) and secondly you need to be able to express your intent of ignoring types (with something like ‘as’) against common sense. A typical example would be:

I did learn that TypeScript supports ‘instanceof’ for reflexion but I couldn’t find anything specific about cast operators, i.e. ‘as’. So I wrote up a language spec request called Please add support for explicit casts with ‘as’ keyword. The Microsoft folks replied promptly and provided a solution that works for me:

var toaster : Toaster = <Toaster>bunnyOrToaster;

This notation is called “type assertion” and will throw an error if ‘bunnyOrToaster’ is not of type ‘Toaster’. In ActionScript ‘as’ does not throw and simply returns NULL if the types don’t match. But that behavior can easily be emulated by using try/catch. So I am fine with that.

Does TypeScript support inheritance?

Yes, TypeScript does support inheritance. You can define classes which can derive from other classes and may implement interfaces. Digging deeper into the inheritance topic I usually get interested in encapsulation and interfaces.

Can I encapsulate members and methods in private and public sections? (yes, that’s what I want)

Is everything public? (bad)

Can I use protected? (nice to have, but I don’t need it)

Is ‘class’ a primitive type?

TypeScript supports public and private at compile time. Once you cross-compile to JavaScript everything is public. That’s fine with me.

Having ‘class’ as a primitive type is very useful for things like factories.

var c : Class = MyClass;
var x : MyClass = new c();

TypeScript does not support ‘class’ as a primitive type. But they have this weird thing called “brands”. Here is the answer to my language spec request called Please add a new primitive type ‘Class’ :

A class in TypeScript is a combination of two things: A construct signature and a brand. Brands are unique to each class, so you don’t care about those. Your question then boils down to: what type will be assignment compatible with every class? Consider this:

interface Class {
new (args:any): any;
}

This interface will be assignment compatible with any class because all classes will have a construct signature with one or more arguments that returns something assignment compatible with any. You can limit this further depending on your use case.

I first didn’t get the idea. But then I tried it and just by including that definition of Class I could use Class as a generic type for classes!

Does TypeScript support interfaces?

My questions are simply:

Can one class implement multiple interfaces, or only one?

Can I determine whether an object is an instance of a class that implements an interface?

Yes, TypeScript does support interfaces and classes may implement multiple interfaces.

But unfortunately you cannot use ‘instanceof’ for interfaces. For example this will give you a syntax error:

Not a bug. Interfaces are purely type information, and TypeScript’s type information is only present at compile time. Instanceof is a runtime feature of JavaScript so has no idea what TypeScript types originally existed.

Identifying the lineage of objects in TypeScript must be done the same way it is done in JavaScript today, such as by setting sentinel values during construction or by examining the structure of the object (eg. if it has a ‘talk’ property it must be an animal). TypeScript could possibly provide a library method to do this for you, but it’s a difficult thing to do right since the type information is not available at all at runtime.

This is a bit disappointing. So TypeScript supports interfaces but you can’t really use them for reflection? In my opinion you can’t offer a feature that extends JavaScript and then not support it in situations for it was designed for with the argument that JavaScript does not support that feature. I admit it’s work, but I have implemented it in my ActionScript to JavaScript cross-compiler. You need to emit a table to the JavaScript code that maps from a class name to its implemented interfaces. At compile time you need to statically analyze whether the right hand side of an ‘instanceof’ expression is an interface. If so, your cross-compiler has to ‘virtualize’ the expression and emit something like “adobe.instanceOf(a,b)” instead of “a instanceof b”. It’s work but it can be done. If even I can do it, Microsoft can certainly do it.

Can I split up my TypeScript project into smaller pieces?

Yes, you can. They call it “modules”. It’s pretty cool especially because Modules are “open ended”, meaning you can add more implementations to pre-existing Modules.

Can I use other JavaScript libraries with TypeScript?

Yes, you can. And it’s pretty easy. You just “import” their declaration source files. By convention declaration source files end with *.d.ts and contain interfaces and APIs provided by the JavaScript library you want to include. It’s pretty easy to write those declaration source files and I suspect that very soon you’ll find declaration source files for all major JS libraries.

I have to admit that TypeScript beats Dart at this feature. Dart’s JS interop library is just awkward to use and most likely dog slow.

What’s the verdict?

I have to say that TypeScript gets good marks for most of the items on my checklist. The only fly I could find so far is missing support for ‘instanceof’ interfaces.

I could probably go on for hours kicking TypeScript’s tires but I think the questions above are probably the most important ones. Once I find answers to those language feature questions I usually move on and have a look at the generated JavaScript. And that’s a whole other ball game…