Babel strips TypeScript types without checking them
Babel transpiles TypeScript by erasing types, but it never type-checks. Pair it with tsc --noEmit to catch type errors before deployment.
08 Apr 2026, 17:09 UTC

The problem: a type error reached production because Babel never saw it
You add Babel to your TypeScript project to compile modern syntax for older browsers. The build succeeds, you deploy, and a runtime error appears: a value you typed as `string | null` was used where only `string` was allowed. The error existed in your source, but your pipeline never stopped it.
The takeaway is practical: Babel is a transpiler, not a type checker. Use it to transform and polyfill code, but keep a separate `tsc --noEmit` step to catch type errors before deployment.
What @babel/preset-typescript actually does
When you add `@babel/preset-typescript`, Babel parses TypeScript syntax and strips type annotations. It turns interfaces, type aliases, and parameter types into plain JavaScript. It does not run TypeScript's type checker, so it will not flag mismatched types, missing properties, or incorrect return values.
This is why a file like this passes through Babel cleanly:
function sendAlert(message: string) {
console.log(message);
}
const optionalMessage: string | null = null;
sendAlert(optionalMessage);
Babel removes `: string` and `: string | null`, then emits JavaScript that calls `sendAlert(null)` at runtime. The type error is invisible to Babel.
Configure preset-env with explicit targets
Babel's `@babel/preset-env` chooses transforms and polyfills based on your targets. Without targets, it may over-transpile for modern browsers or omit polyfills your older users need. Put targets in `babel.config.json` so the whole project shares one rule set.
{
"presets": [
["@babel/preset-env", {
"targets": {
"browsers": ["last 2 Chrome versions", "last 2 Firefox versions", "Safari >= 15"]
},
"bugfixes": true
}],
"@babel/preset-typescript"
]
}
The `bugfixes: true` option is the default in Babel 8 and aligns preset-env with newer spec behavior; older Babel 7 examples may omit it and produce different output. Check your version before copying configuration from the web.
Worked example: run Babel, then check types separately
Run these commands from your project root. No special permissions are required.
- Create `src/user.ts` with a type error:
function greet(name: string) {
return `Hello, ${name}`;
}
const maybeName: string | null = null;
greet(maybeName);
- Transpile with Babel:
npx babel src/user.ts --out-file dist/user.js
Expected result: Babel exits successfully and writes `dist/user.js` with the type annotations removed. Risk: if `dist/user.js` already exists, Babel overwrites it.
- Type-check without emitting:
npx tsc --noEmit
Expected result: `tsc` reports the type error and exits with a non-zero status. It emits no files because of `--noEmit`, so this command is safe to run in CI or locally. If your project has no `tsconfig.json`, create one first.
A practical way to verify the separation is to compare exit codes: `echo $?` after each command on Unix-like shells. Babel should return `0`; `tsc --noEmit` should return a non-zero value for this file.
Trade-off: speed versus type safety
Babel is typically faster than `tsc` because it skips type analysis. That speed is useful for builds, but it is not a substitute for type checking. Source maps can help you debug transpiled output by mapping it back to TypeScript, but they do not catch type errors before code runs.
Use Babel for transpilation and `tsc --noEmit` as a gate in your CI pipeline or pre-commit hook. Run `npx babel --version` first to confirm you are on Babel 8 if you rely on its default `bugfixes` behavior.
Checklist before you ship
- Install `@babel/preset-env` and `@babel/preset-typescript`.
- Set explicit browser or Node targets in `babel.config.json`.
- Add `tsc --noEmit` to your CI build and require a zero exit code.
- Confirm Babel's major version with `npx babel --version` before applying Babel 8-specific examples.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.