My experience with TypeScript

My experience with TypeScript

I have spent the first half of this year with building a fairly big node.js application using TypeScript. Below you can find some information about my experience.

What is Typescript?

Typescript is one of the new altJS languages. It's essentially a typed superset of JavaScript. The easiest way to understand the basics is by checking out some of the before-after examples here.

Now that we know what TypeScript is, let's go through some of the things I really liked about the language:

  • Most features are compatible with ECMAScript 6
  • unlike other altJS languages, TypeScript feels like and it really is JavaScript
  • fat arrow syntax for closures is great
  • Type definitions are available for most bigger javascript projects
  • modules/classes are providing much needed namespaces
  • generics
  • compiler can pick up issues even through type inference
  • emitted source code is easy to debug (and you can generate source maps, too)
  • great tooling (even on non-windows platforms)
  • tsc is your friend

Not surprisingly though, TypeScript being such a young technology meant that I had run into lots of smaller and bigger issues.

Gotcha-s

"starts from JavaScript, ends with JavaScript" - sort of

One of the biggest selling points of TypeScript is the fact that existing JavaScript files are valid TypeScript files. Unfortunately, this assumption breaks immediately once we try to compile multiple files in one go. Consider the following snippet:

My experience with TypeScriptS

In node.js context, only exported variables are part of the global namespace and so it's very typical that two javascript files are sharing top level, non-exported variable names. This, however, breaks TypeScript since it treats multiple files as a single namespace (which by the way makes perfect sense in front-end context).

The workaround is to wrap both files into TypeScript modules like:

My experience with TypeScriptS

While this is a very straightforward change (and compile checked, too), it does mean that the conversion won't be as quick as advertised.

where is my property?

My experience with TypeScriptS

Note that TypeScript disallows arbitrary property access.

types, types, types - not so fast!

And while we are at types, consider the following valid JavaScript code:

My experience with TypeScriptS

Again, TypeScript is just trying to do the right thing from a type system's point of view. Generally, I am OK with changing my code for better type safety (that's why I am using TypeScript after all), so needless to say that I found it a bit strange that you can treat a method argument in the same position both as co- and contra-variant and apparently the new generics implementation exhibits similar issues as well.

type my prototype

And then there is the situation where you might need to provide type definitions for methods that were added to the prototype of a native type. The workaround is to extend the definition of the given built-in type. For example, here is the type definition for Function.prototype.myMethod:

interface Function { myMethod(callback: (args:any) => any ): any; };

(However, accessing __proto__ methods is still problematic)

life in a mixed environment

The next thing you need to figure out is how to separate generated js files from your js +ts sources. One typical solution is to put all generated source file into a specific folder (for example: ./ts). While this solution solves the problem of excluding generated files from source control. It also means, however, that the folder structure of your source files and the generated source files will be different. Besides the mental switch this leads to an issue: your import references will be confusing.

My experience with TypeScriptS

order of definitions matters - duh!

Inheritance only works if a parent class is declared before a child class. What's even worse is that this particular issue manifests itself only at runtime.

filling the gap

The complier right now does not take a directory as source, so you will need to manually identify ts files in your project. Here is a one-liner identifying ts files in a node project:

./node_modules/typescript/bin/tsc -w —out ./ts `find . -name "*.ts" | grep -v node_modules | grep -v "\.d.ts"`

this and that

TypeScript won't bind this for you and while this is not completely surprising, it's something you may expect after being forced to use this for property access within classes.

Take a look at this example:

My experience with TypeScriptS

typescript 0.9 on nix - not speedy yet

TypeScript 0.9 contains a lot of exciting new features, including generics but the compiler appears to be somewhat slower than 0.8. Depending on your project size, you may or may not see this as a problem but it certainly can be an important consideration.

My experience with TypeScript

small annoyances

  • type definitions can clutter your source files
  • no way to pass your type denition references as command line arguments
  • no built-in way to manage different versions of type definitions
  • no command line REPL
  • no way to pipe compiler's output
  • UTF-8 in source files is not honored (update: this is now fixed)

Conclusion

TypeScript is clearly in an early preview stage right now but if you are into using a type system and better tools for Javascript development, then even in its current form it's definitely worth giving a shot. On the other hand, dynamic language fans should probably look elsewhere but that's for another post.