Editor’s note: This post was last updated on 30 July 2021. Some sections were rewritten to be accurate with the updates in Babel 7.15.
Since Babel 7 was released in 2018, projects using Babel can use TypeScript without ever needing to complicate their builds with the TypeScript compiler.
But what are the differences between using Babel and the TypeScript compiler? And should you use Babel or TypeScript for your next project?

The differences between Babel and TypeScript
There are some major differences between using TypeScript and using TypeScript with Babel.
In this post, we’ll look at the five most important differences.
1. No type checking in Babel
Babel doesn’t care about your fancy TypeScript types. It just throws them in the trash, without checking that they’re right. The example below compiles without any errors or warnings with Babel, but not with TypeScript:
const myCoolString : string = 9;
9
is definitely not a string Babel.Removing the types can be excellent for quick prototyping where you want the code to compile, even if your types aren’t on point.
If you’re going through the effort of typing things, at some point you’ll probably want to check that they’re right. Luckily, it’s not a big deal. You can either let your editor take care of it or run tsc --noEmit
, which typechecks your project without compiling anything.
2. Babel couldn’t do const enums
TypeScript by default compiles an entire project at once, while Babel only compiles one file at a time.
Previously, this meant that Babel did not support TypeScript features that required reading multiple files — such as const enums
.
However, this isn’t true since Babel 7.15, which was released 26 July 2021. This essentially means that if you’re on the newest version of Babel, you should be able to compile all valid TypeScript codebases.
3. Decorators and metadata: TypeScript has an edge
TypeScript was a bit early to the decorator party (if you’re unsure what a decorator is, this is a fine introduction to decorators). After TypeScript implemented decorators, the decorator proposal has changed multiple times and is still not finalized.
What that means is that currently the ECMAScript spec and TypeScript don’t quite see eye-to-eye on how decorators should behave. Babel’s plugins follow the ECMAScript spec, which means that Babel doesn’t compile decorators the same way that TypeScript does. Luckily for us, Babel has a legacy
mode to compile decorators with the old behavior.
Simply add the Babel plugin
“@babel/plugin-proposal-decorators”
with the legacy
option set to true
.
There’s one other TypeScript decorators feature we should talk about: emitDecoratorMetadata
.
TypeScript normally erases all type information so it doesn’t exist at runtime. emitDecoratorMetadata
is a feature that keeps the types around for classes and methods that have a decorator applied to them.
Having the type at runtime allows us to do all sorts of fancy things, such as dependency injection and mapping the TypeScript types to types in an SQL database.
The feature sees reasonably heavy use in those two areas, with libraries such as TypeORM, TypeGoose, inversifyJS, and even Angular’s dependency injection system depending on this feature.
As Babel doesn’t care about your type information, this feature requires a custom plugin, babel-plugin-transform-typescript-metadata. Adding that plugin along with the plugin-proposal-decorators
mentioned before should give Babel feature parity with TypeScript in regards to decorators.
4. Babel excels at custom transformations
Babel is much more extensible than TypeScript. There are plenty of plugins that optimize your code and help you strip out unused imports, inlines, constants, and much more.
While TypeScript has its own Transformer API which allows for custom transformations, the Babel ecosystem is both richer in plugin choices and much more accessible.
If you need custom transformations, you’ll need to use Babel. The good news is that most TypeScript tools allow you to both use TypeScript and then run the code through Babel afterwards, to get the best of both worlds. But this obviously comes with additional complexity in your build-chain.
5. TypeScript and Babel have similar performance
Comparing Babel and TypeScript in regards to performance is difficult and probably won’t give you the full picture. TypeScript that performs type-checking will definitely be slower than Babel as there’s extra steps.
To reach approximately equal speed you can mitigate that slowdown by using something like fork-ts-checker-webpack-plugin which runs the compilation without types in one process and the type-checking in a background process.
Of course, as anyone who’s tried to configure webpack knows, JavaScript toolchains feel immensely complicated. You have source-map plugins, caching, choices between how many threads you should use — the list goes on. No simple benchmark can take the full story into account, but if you’re expecting a many-fold increase using Babel over the TypeScript compiler, you’ll have to look for your performance gains elsewhere — perhaps your bundler?
Which should you choose: Babel or TypeScript?
At this point, TypeScript and Babel are approximately equal in the role they can play in your build chain. Babel now has full support for const enums
, decorators, and decorator metadata.
The only downside using Babel is that you will need to run your type-checking as a separate process.
If you already have a build pipeline that works for you, I don’t see any compelling reason to switch. However, if you’re starting out on a project, I would probably tend towards using the TypeScript compiler, potentially via something like ts-loader. Then later on if you find you need some transformation only Babel provides, you can pass the transpiled TypeScript output to Babel afterwards.
It’s a little too complicated for my tastes, but hey — nobody ever said JavaScript build toolchains were easy.
Do you have any experiences with TypeScript and Babel? I’d love to hear them. @GeeWengel
LogRocket: Full visibility into your web and mobile apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.
Try it for free.
Hey I came across your article and found the part on decorators and metadata very useful but I just thought I would let you know about this plugin: https://github.com/leonardfactory/babel-plugin-transform-typescript-metadata which they describe as ‘Babel plugin to emit decorator metadata like typescript compiler’.
Thanks for bringing this up! We’ve updated the blog post to include information on this plugin.
Nice article. Thank you