Why we chose TypeScript: a history of developers from Reddit

Original author: Niranjan Ramadas
imageAbout half a year ago, Steve Reddit CEO announced that we were redesigning the site. The main question here is how exactly do we do it. Nowadays, front-end development is very different from what it was at the time when Reddit was born. Now there is a huge selection of options for each subsystem of the web application. How to render pages? How to style content? How to store and maintain pictures and video files? How to write code? In modern conditions, none of these questions has a ready answer.

One of the first such questions to which we needed to find the answer was: "Which language to choose?".

On the richness of choice and language requirements


Oddly enough, our language for the frontend did not have to be JavaScript. Ultimately, no matter what language is chosen for this purpose, the code written in it is still compiled in JavaScript. However, what exactly the code is compiled into is perhaps less important than what the developer writes. The choice of language was not easy. Here's what we had to consider:

  1. BuckleScript
  2. ClojureScript
  3. CoffeeScript
  4. Elm
  5. ElixirScript
  6. JavaScript 2016 and future language versions
  7. JavaScript + annotations
  8. Nim
  9. Purescript
  10. Reason
  11. TypeScript

And this, by the way, is far from a complete list. Each language has its pros and cons, so in order to help ourselves choose one of them, we formulated the following requirements:

  1. It must be a strongly typed language. Types, at the micro level, play the role of documentation. They help, to some extent, ensure the correctness of the code, and, more importantly, simplify refactoring. Another consideration that made us look for a strongly typed language was development speed. We tried to find a strongly typed language, because we wanted to speed up the work. Such an idea runs counter to the typification vision that many programmers have developed. Namely, it is generally accepted that this is an additional burden on the developer, which reduces the speed of work. However, increasing development speed also means increasing the likelihood of errors. We needed typing so that the code contained as few errors as possible, even if they were written quickly. Strong typing is also useful in fast-growing projects.

  2. There must be good supporting tools . Given what we were planning to do (a serious redesign of the site), we did not have time to independently create a significant number of auxiliary tools. It was very important that we could get started quickly using ready-made open source solutions. More specifically, these are the specific tools in question. This is integration with popular build systems (for example, with Webpack), support for the linter, simple integration with test frameworks. If the integration of auxiliary systems for some language was not obvious, we no longer considered this language.

  3. The language was to be used in serious projects . If the language looked good, but in reality was used only in small projects of individual enthusiasts, it could well be inappropriate for our task. In addition, if the language is not used in serious projects, questions arise about how long such a language will last, and how quickly the language developers will respond to messages about errors found in it.

  4. Our developers must learn the language quickly enough . The above list has wonderful languages, the only negative of which is the too long time that developers need in order to master them. Among them, I would like to mention Elm and PureScript. We seriously discussed the issue of their use. However, in the end it turned out that their implementation would mean too much work necessary for the development of new programming concepts by developers who are not familiar with them, for them to reach a level that allows them to work productively on a project.

  5. The language should work on both the client and the server . At Reddit, SEO is very important, so the lack of a universal system for delivering pages ready for display in the browser is a big problem.

  6. Good library support . We were not going to write everything from scratch. There are some tasks that require reliable, time-tested libraries. We wanted us to have the opportunity to choose what we need from existing libraries.

After considering these requirements, we settled on two options. The first is TypeScript. The second is JavaScript + Flow. But, before making the final choice, we wanted to understand the features of TypeScript and Flow as well as the differences between them as best as possible.

Compilation or annotation?


One of the important differences between TypeScript and Flow is that TypeScript is a language that compiles into JavaScript, and Flow is a collection of type annotations that can be added to JavaScript code. The correctness of annotated code is checked by a static analyzer.

The above differences directly affect how programs are written. Take a look, for example, at work with enumerations in TypeScript and Flow.

TypeScript

enum VoteDirection {
  upvoted = 1,
  notvoted = 0,
  downvoted = -1,
};
const voteState: VoteDirection = VoteDirection.upvoted;

Flow

const voteDirections = {
  upvoted: 1,
  notvoted: 0,
  downvoted: -1,
};
type VoteDirection = $Keys;
const voteState: VoteDirection = voteDirections.upvoted;

Since TypeScript is a compiled language, it can be used to create types that are defined at runtime. In Flow, types are just annotations, so we cannot rely on any code transformations to create type representations at runtime.

However, TypeScript, due to the fact that it is a compiled language, has certain disadvantages. When integrating TypeScript into an existing codebase, it is likely that the compiler will complicate the build process. We have an established build process using Babel and the transpilation layer. There are several optimizations that I would like to keep even when switching to TypeScript, so I needed a way to integrate TypeScript, which would not destroy the working scheme that already exists. The implementation of TypeScript would be a much more complex build process.

In contrast to TypeScript processing, Babel automatically removes Flow type annotations. If we chose Flow, the process of building the application would not be complicated.

Code Validation


In the area of ​​code validation, Flow usually performs better than TypeScript. In Flow, by default, it is forbidden to use types that allow a value NULL. TypeScript 2.x added support for types that are not allowed NULL, however, you must enable this feature yourself. Flow also displays types better, while TypeScript often accesses types any.

In addition to types that allow value NULLand type inference, Flow is better in matters of covariance and contravariance ( here is the material on this topic). One of the typical problem situations here is working with typed arrays. By default, arrays in Flow are invariant. This means that the following construction in Flow will cause an error:

Flow

class Animal {}
class Bird extends Animal {}
const foo: Array = [];
foo.push(new Animal());
/*
foo.push(new A);
        ^ A. This type is incompatible with
const foo: Array = [];
                ^ B
*/

However, an attempt to do the same in TypeScript fails without error messages.

Typescript

class Animal {}
class Bird extends Animal {}
const foo: Array = [];
foo.push(new Animal()); // в typescript всё нормально

You can find many more similar examples, however, the general conclusion is that Flow performs much better in type checking than TypeScript.

Ecosystem


Everything that has been said so far speaks about the benefits of Flow. It is easier to integrate into the project, it copes better with type checking. Why did we stop at TypeScript?

One of the most important benefits of TypeScript is its ecosystem. It features awesome library support. Almost all the libraries that we used either have type descriptions in the libraries themselves, or are presented in DefinitelyTyped . In addition, TypeScript has excellent IntelliSense support in VSCode and in plugins for other popular editors that we use (for example, Atom and SublimeText among them). Moreover, we found that TypeScript can handle JSDoc annotations. This turned out to be especially useful as we switched to TypeScript with JavaScript.

In addition, TypeScript is more "social significance", and there is a feeling that his life will be long enough. There are several large projects using TypeScript (among them - VSCode, Rxjs, Angular, and TypeScript itself), so we have confidence that the set of its capabilities will be able to meet the goals of our project, and that the language in the coming years not going anywhere. As for Flow, what worries us is that it was created to solve specific tasks on Facebook, and that its development will be determined by the same range of tasks. TypeScript, on the other hand, is focused on a wide range of problems, and Microsoft is working on it. All this allows us to assume that if we encounter errors and report them, they will hear us and take action.

In addition, since TypeScript is a superset of JavaScript, we can expect that the development of TypeScript, in particular its support for new types and language constructs, will follow the development of JS. The language and type system will develop in parallel, since work on them is ongoing.

Summary


We chose TypeScript, as we are confident that we will be able to quickly teach all the necessary new developers (the number of our front-end engineers has tripled in the last year). We are confident that the language meets our needs in the redesign of the site. In addition, everything suggests that TypeScript will exist for a long time, and our research has shown that it integrates well with our code base. However, for us the most important thing is the transition to a strongly typed language.

Using a typed language has already brought some results. There are fewer type-related errors in the code, we more confidently perform large refactorings. Embedded documentation now focuses on concepts, rather than describing the internal structure of objects and function parameters. As a result, we can say that TypeScript was exactly what we needed.

Dear readers! Do you use TypeScript or Flow?

Also popular now: