TypeScript and Babel, a match made in heaven

TypeScript is awesome. I 💖 it! It brings powerful type checking to your codebase that helps you find bugs more quickly and form and adhere to contracts more easily. Not to mention the amazing editor experience that comes with adopting it, it’s support in VS Code is seamless and fast!

An unpopular union in the past

TypeScript has always enjoyed a growing user base but there are still a lot of JavaScript developers who have not adopted it. This is due to a number of pain points that have often made it awkward for developers. It generally came down to the need to manage and learn 2 different tool chains, most often TypeScript and Babel. Many JavaScript developers use Babel and don’t want the hassle of adopting TypeScript too. Issues these developers face include:

  • Being dependent on certain Babel plugins.
  • Many tools support Babel out of the box but not TypeScript. An example being Jest the JavaScript testing framework. It compiles your test code using Babel by default so you don’t have to configure anything. However, if you want to test TypeScript code with it then you need to install the package ts-jest and configure Jest to compile code using it.
  • It requires a two step build process; compile TypeScript code with one tool then compile outputted JavaScript code with Babel. This adds build time and complexity.

First class TypeScript support in Babel

The Babel and TypeScript teams are well aware of the popularity of one another and the pain points developers face adopting both at the same time. Luckily for us they have worked together, and with the introduction of Babel 7 developers will have a much easier time adopting TypeScript and using Babel at the same time.

There is a new plugin on the block @babel/preset-typescript. 🎉

This plugin simply strips TypeScript types from your code so that Babel can understand it as plain JavaScript. We do need to use it in tandem with a couple of other Babel plugins however in order to fully support all TypeScript type features; @babel/plugin-proposal-class-properties and @babel/plugin-proposal-object-rest-spread. So our minimum Babel config would look like this:

// babel.config.js
module.exports = {
presets: ["@babel/typescript"],
plugins: [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread",
],
};

Pain points resolved?

Well, yes.

Now we need no additional configuration for tools like Jest as it supports Babel out of the box with no additional configuration. It will find your Babel configuration file and run the TypeScript preset.

You also won’t need to introduce more than one build step either. Your compilation can occur in a single step by compiling with Babel.

Type checking

Now, I’ve cheated a little above. Yes our build can now occur in a single step by compiling with Babel, however the preset @babel/preset-typescript does not perform any type checking whatsoever. It simply strips types out of your code so Babel can understand it as plain JavaScript. So actually, we kind of do need another build step, we need to use the TypeScript tool separately to type check our code.

To do this we need to install TypeScript:

yarn add --dev typescript

Then add TypeScript configuration into a tsconfig.json file:

// tsconfig.json
{
"compilerOptions": {
"esModuleInterop": true,
"lib": ["esnext"],
"strict": true
}
}

This configuration does the following:

  • "esModuleInterop": true — Allows you to use imports exactly as Babel would expect. TypeScript does not have the notion of a default import, you group together all of a modules exports into a single variable via this syntax; import * as React from 'react'. However Babel does not require this and you can use this syntax; import React from 'react'.
  • "lib": ["esnext"]—This allows you to use the latest JavaScript language features.
  • "strict": true — Enables all strict type checking options.

And finally run the TypeScript tool with the --noEmit flag so it does not output any files. You can optionally not use --noEmit and instead use --declaration --emitDeclarationOnly. This will output TypeScript declaration files if you want to bundle them with your build JavaScript code.

tsc --noEmit
# or
tsc --declaration --emitDeclarationOnly

These can also be configured with the TypeScript configuration file.

In conclusion

So now we know how to configure Babel to compile TypeScript code and how to type check our code. The future of types in the JavaScript world looks brighter than ever. Thanks Babel and TypeScript you ⭐️s!