Skip to main content
Home

Huy Dang Lê-Ngô

Senior Front-End Engineer @Slack

Thursday, September 22nd, 2016

Musings about TypeScript

TypeScript 2.0 has officially released today. After working with TypeScript 1.8 for half of a year, its improvements are certainly welcome. However there are a few points, both pleasant and painful, that should be discussed.


TypeScript is a great bridge between typed languages such as C# and Java and JavaScript. This makes it a lot easier to introduce developers to an environment that they are not familiar with, by hiding the JavaScript quirks under its hood. This is great for teams, since they can recycle talent to be leaner with only a minimal amount of friction.

TypeScript also introduces a class of compilation errors that should help developers write correct code. For a interpreted language, this is extremely helpful as it reduces the cognitive load on the developers to let them focus on errors that are more important, such as complexity and state. Moreover, I can't stress enough how important that TypeScript 2.0 also supports non-nullable types. This addition should cut a large portion of common mistakes that a developer can make.

Adding to the fact that typed languages add a lot of features that helps coding, such as code completion and refactoring magic, TypeScript has also added, in the 2.0 release, more control flow analysis, which makes it get up to speed and to par with its main competitor, Facebook's Flow.

With the 2.0 release, the tooling has improved tremendously, and it is now quite easy to convert a JavaScript project to TypeScript. TSD and Typings were amazing package managers. However, in a world where we are slowly moving away from multiple package managers, it is a blessing that typings are now managed with @types scoped NPM packages.


As amazing as the additions are, I find the type definitions over untyped source files paradigm to be incredibly flawed. Unless a project is built from the ground up with the typed language, the maintainer of the project have to add and maintain a definition file within the project. This mean a lot of boilerplate to set up tests, validate every release twice or more (once for each languages), and a lot more of man-hours. If the maintainer is not willing to do that, the project is at the whim of the community, in TypeScript's case, DefinitelyTyped. These definition files maintained by the community often lag behind the actual implementation of the library, since they are only maintained by volunteers.

You could say that you could create those definition files yourself to benefit from typings of third-party libraries, and it is indeed the approach that Flow is recommending. However, creating such a file means that you have the responsibility to maintain the definition files on top of modifying your source code on any breaking changes. I can't think of any other languages where you need to maintain the interfaces and API of the libraries you currently use.

There's always the possibility of using the require() construct to import the dependencies. However, those dependencies will not benefit from any typings. Indeed, anything that is imported using the require() function will be considered as any, throwing any benefits of using a typed language out of the window and adding even more boilerplate. This is incredibly frustrating when I'm looking for more obscure libraries that don't have any typings, either maintained by the author or by the community.

There also seems to be a lot of obscure compilation errors that happens which are easily fixed by appending as any, :any or <any>. While this is a huge shortcut, this is a lot easier than writing all of the boilerplate code (the corresponding interfaces) that will rarely, if ever, be re-used. If you use any to fix your typings issues, you are throwing away all the benefits of using a typed system and you might as well not use the typed system in the first place!


Overall, with my experience of working on a codebase of around 18k lines of TypeScript code, I am not too fond of TypeScript. I find that under the React/Redux ecosystem, the cons greatly outweight the benefits. I do not need typings on my components, since there are already propTypes. I do not need to share interfaces for action creators, actions, reducers and stores, since I am using ducks. Moreover, since there are no side-effects naturally, I only go from a plain old JavaScript object to another, and the benefits from using a typed language are not very apparent.

I believe that TypeScript will fulfill a large segment of the market. However, it is definitely not a perfect fit for every project, and it is certainly not a panacea for frontend development woes. If anything, this just adds even more load on to the JavaScript fatigue.