type-only imports — A new TypeScript feature that benefits Babel users
You’ve decided you’re going to use Babel and write your source in TypeScript. But what happens when you’re sharing TS types across module boundaries? How should Babel handle those imports and exports?
Let’s briefly cover how Babel and TypeScript work together.
TypeScript does two things:
- Adds static type checking to code you would traditionally write as JavaScript.
- Transpiles TS+JS code to a variety of JS flavors.
Babel also does that second thing. Babel’s approach (specifically transform-typescript plugin) is to simply remove types, then transpile. This allows you to use Babel for all of its benefits, while still being able to feed it ts
files.
Babel is going to remove (elide) any import
declarations that are only used as types.
Source:
// example.ts
import { Color } from "./types";
const changeColor = (color: Color) => {
window.color = color;
};
Babel transpiled output:
// example.js
const changeColor = (color) => {
window.color = color;
};
With confidence, Babel can remove that declaration, analyzing only this individual file. Issues arise when Babel can’t possibly know if a particular import is a type that should be removed or an actual value that should be kept. This can happen when utilizing re-exports.
// example.ts
import { Color } from "./types";
export { Color };
Here, Babel cannot tell by looking at example.ts
that Color
is in fact a type. Babel would be forced to incorrectly leave this declaration in the transpiled output.
Why does this happen? Well, Babel explicitly processes a single file at a time during its transpilation process. Presumably, the babel team doesn’t want to have to build in the same type resolution process as TypeScript does, just so it can remove those types.
Enter, isolatedModules
isolatedModules
is a TypeScript compiler option meant to act as a safeguard. The type-checking provided by tsc
when the isolatedModules
compiler flag is turned on will report type errors that, if left…