Why combine Babel and TypeScript?

It can feel like Babel and TypeScript have largely overlapping use cases: both allow you to use modern Javascript features, even before all relevant browsers support them. Thus, do you even need Babel when you use TypeScript? Or conversely: now that Babel has added TypeScript support, can you replace TypeScript with Babel? What's the difference? Why does a project like Create React App combine the two?

To learn the answers to these questions, it helps to consider TypeScript as doing three things:

  1. It does type checking for your application.
  2. It strips type annotations.
  3. It transforms modern Javascript into versions understood by relevant browsers.

To illustrate these steps, let's consider how the following code is affected by each of those steps:

const logNumber = (num: number) => console.log('The number is:', num);

The first thing TypeScript will do is to check whether you satisfy all the constraints set by the type annotations: type checking. After doing so, the code will look like this:

const logNumber = (num: number) => console.log('The number is:', num);

That's right: it's exactly the same. Type checking does not actually alter your code; all it does is warn you if you break the assumptions encoded in its type annotations. In other words: if you were to call logNumber('Not a number') elsewhere in your code, TypeScript will warn you that you probably made a mistake — but it will not modify your code.

Or at least it won't before step 2: stripping type annotations.

const logNumber = (num) => console.log('The number is:', num);

In this step, TypeScript removed everything that is TypeScript-specific (i.e. : number), preserving only that which is valid Javascript. In fact, an explicit design goal of TypeScript is to produce "clean, idiomatic, recognizable JavaScript code".

However, that arrow function will still be problematic for visitors using Internet Explorer. To remedy that, TypeScript can also transform this Javascript to older — but more widely supported — syntax:

var logNumber = function (num) { return console.log('The number is:', num); };

Even plain Javascript projects often have the requirement that they should support older browsers. For the vast majority of those projects, Babel is the tool of choice to perform that transformation. And while you could always use Babel for that even in TypeScript projects, the increased complexity of setting up additional tooling often meant that that was not worth it.

With the release of Babel's TypeScript plugin, however, Babel is now also able to perform step 2: the stripping of type annotations. That means that Babel can now handle every step that actually involves changing your code, with TypeScript running independently — and that's a game changer.

Why? First of all, it means that existing projects can now introduce TypeScript without having to introduce a new tool to their toolchain. With the addition of a single Babel preset, developers can start using TypeScript without having to actually run the TypeScript compiler. They will still need to use e.g. an editor with TypeScript support to benefit from type checking, but doing so will not affect the way their code is built and run.

More important, perhaps, is the point of view of tooling authors. Projects like Create React App have many different users with many different needs. When part of their user base uses Babel to transform their code and another part uses TypeScript, they will have to test all those different configurations, making sure that e.g. Sass works with both Babel and TypeScript, and to verify for every bug report whether the reporter is using Babel or TypeScript. Being able to use consistent tooling saves a lot of work and prevents a lot of bugs.

In other words, tooling authors can now add support for TypeScript without negatively affecting the part of their user base that does not use TypeScript, while limiting the divergence between those who do and those who don't.

Of course, this also benefits developers using those tools. Adding a layer of type checking on top of the tooling used by the rest of the ecosystem, rather than replacing parts of that tooling with TypeScript, allows you to build on a more widely tested foundation and to leverage existing support channels and documentation. With that, TypeScript and Babel appear to be a winning combination.


This work by Vincent Tunru is licensed under a Creative Commons Attribution 4.0 International License.