Using TypeScript with AngularJS 1.x

Using TypeScript with AngularJS 1.x

We have been using AngularJS framework in our projects for quite a long time. It really simplifies the DOM manipulation thanks to it’s two-way data binding, offers great flexibility and makes structuring the app easy. It also has a really huge community support. Recently our client decided to switch from plain JavaScript to TypeScript in order to have better control over the ever-changing codebase. Below are some thoughts about using TypeScript in cooperation with AngularJS after a few weeks of work:

The obvious profit from using TypeScript is compile time syntax check and type checking. This prevents many typical bugs and typos from getting into production code. It also makes refactoring the code easier, because any missing change is immediately visible as a compiler error, instead of run-time exception that may appear at the least expected moment. Of course to benefit from this you have to use the typing mechanisms strictly and not put any everywhere in code. This deprives JavaScript from some of its flexibility, but also prevents many constructions that are generally considered a bad practice.

Apart from semi-strong typing, one of the biggest strengths of TypeScript is the classical inheritance. JavaScript prototypal inheritance differs a lot from standard classes and instances, that are familiar for many C++/Java/C# developers. It is one of the reasons they are used rather reluctantly, although it is a really powerful mechanism. TypeScript allows to define classes and interfaces with standard inheritance mechanisms just like in Java, together with public/protected/private access modifiers. This makes extracting common behaviour and specialization really easy and much more readable and maintainable.

However, when writing TypeScript code you cannot forget that it gets compiled to plain JavaScript underneath, so nearly all of its quirks and flaws are still applicable. You have to remember about the falsy values, ==/=== comparison logic, null/undefined/NaN weird behaviors and so on. The meaning of the `this` keyword in TypeScript is more straightforward – the compiler handles common var that = this; substitution for you. Anyhow, this works only as long as your functions are called from TypeScript code, otherwise `this` can be set to anything by the caller. This applies for example to functions called by some third-party directives. To deal with such cases you can use the fat arrow syntax – functions defined this way, no matter how called, will always have a reference to the expected this object.

Using TypeScript with AngularJS is not a problem. You just have to learn a bit different framework boilerplate syntax that gives exactly the same result after compilation. The main benefit is that you can define clear interfaces for your services. Typings for AngularJS bult-in services and types can be downloaded for example from DefinietlyTyped project repository (https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/angularjs). Unfortunately HTML templates do not benefit from this a lot. They are still just plain, dumb HTML files, so there is no type checking for interpolated values and directives attributes. That’s why defining interfaces for controllers or particular scopes makes little sense.

One last shortcoming I would like to mention is that after compilation the line numbers from TypeScript sources can differ a lot from those in the output JavaScript files. This makes debugging a bit trickier, because you cannot easily jump back and forth between browser and IDE. You have to find a proper line in the JavaScript code first and only then you can switch to your IDE and look there for corresponding statement in the TypeScript source. The generated JavaScript is however very readable, so this is not a big problem during development.

To sum up, the benefits from using TypeScript with AngularJS are obvious and there are no pitfalls in this approach. However, you should not rush to rewrite all your code into TypeScript to get all the fancy typings and syntactic sugar at the very moment. TS is fully interoperable with JavaScript, so you can start using it now for new features and gradually refactor existing code into TypeScript while still being able to keep up with your release schedule seamlessly.

Will TypeScript replace JavaScript one day completly? I do not think so. It is great for enterprise-class, well structured projects with lots of client-side logic, but it lacks most of the JavaScript flexibility and simplicity that is desirable in many applications.