We're proud to be recognized as a Leader in the 2024 Gartner®️ Magic Quadrant™️ for Collaborative Work ManagementGet the report
Single-Page Applications are a powerful way to build rich applications in the browser but as the application grows, so does the code complexity. Asana has a code base with hundreds of thousands of lines of JavaScript which over time has become increasingly difficult to work with and maintain. After trying many techniques to mitigate these problems we concluded that we needed a different language, one that compiles to clean, predictable JavaScript and supports optional strong types. We decided that language was TypeScript.
Regardless of the language that we write in, there is a lot of JavaScript out there — both our own and open source. Integrating with existing code is simpler if we write in a language that produces simple, clean JavaScript. For example, if we write a class we would like it to compile to an idiomatic prototype definition in JavaScript that we can subclass in our existing JavaScript code if necessary.
People who know JavaScript can more easily learn a new language if the language maps closely to JavaScript. A related point is that a closer mapping between the languages makes the performance of the generated JavaScript easier for people to reason about. It also reduces the need to drop out of the new language and write raw JavaScript.
TypeScript provides all of this. It compiles to unsurprising JavaScript. It’s easy to call between compiled JavaScript from hand-written JavaScript. Understanding JavaScript that came from TypeScript is not a problem.
JavaScript has a large and active open source community which is consistently developing new libraries, frameworks and tools. We wanted to make sure that we would continue to have strong tooling support for our new language and be able to integrate easily with the larger JavaScript community. TypeScript fits this choice naturally: IntellJ/WebStorm has strong support for TypeScript and DefinitelyTyped is a thriving community that provides TypeScript definitions for many open source libraries, making integrating with existing libraries easier. TypeScript also has great build tool support through actively maintained gulp/grunt plugins for compilation, linting and type definition bundling.
Strong typing allows the compiler and IDE to catch errors early. In a small code base this doesn’t matter a lot but in a large code base errors become easier to make and tests take longer to run. There is a large productivity difference between finding out about errors while you are coding and finding out when your tests run several hours later.
Refactoring support and better code navigation also make a huge difference to developer productivity. Many of us have worked on large code bases written in strongly typed languages and believe that safe, easy refactoring resulted in a higher quality code base. In our current code base there are many changes that we want to make but we are scared of what we will break when we make the change.
This is all somewhat controversial and opinionated, but after accumulating experience in Java, Scala and JavaScript, many of us feel this way. It’s interesting that even Guido van Rossum seems to be moving in this direction.
So far, TypeScript seems to excel at all of this. Its type system is surprisingly capable and IntellIj’s support for the language is good enough that many of our mistakes are caught before compilation.
All that said, static typing can cause more pain that it is worth at times, including when people are learning a language. We are happy that TypeScript allows static types when we want them but keeps them optional.
The arguments above in favor of static typing are pretty common. There are also some more surprising benefits.
First, static typing helps us to ensure that the client and server agree on a protocol. Without static typing it can be hard to know whether a field in a RESTful response is being used by the client, especially if it has a common name. With static typing you get a compilation error if you remove a field that is still being used.
Second, static typing allows us to skip checks that would otherwise be required at runtime. For example, React.js will see significant performance improvements because of this and we hope to be able to take advantage of this in future React releases.
Moving to TypeScript for our browser code is just one of several large changes we are making to improve the stability and performance of Asana. We will have more blog posts coming soon about the other changes.