BeCuriouzBeCuriouz

Learn something new every day

🔷 TypeScript
🏷️

import type: Telling TypeScript "This Is Just a Shape"

💡 import type marks an import as erasable-at-compile-time, which single-file transpilers under isolatedModules require because they can't infer whether a name is a type or a value.

When you import { User } from './models', are you importing a value (something that exists at runtime) or a type (something that vanishes after compilation)? TypeScript usually figures this out, but the answer matters for how your code is emitted. A type-only import makes it explicit:

ts
import type { User } from './models'   // erased entirely
import { saveUser } from './api'        // kept at runtime

The import type line is guaranteed to be erased from the compiled JavaScript — no require, no import statement survives. This prevents accidental runtime dependencies and sidesteps circular-import problems, since a type-only edge simply disappears. You can also inline the marker per-specifier: import { type User, saveUser } from './models' keeps saveUser but erases User.

This becomes essential under isolatedModules, a compiler flag that requires each file to be transpilable on its own, without cross-file type information. Tools like Babel, esbuild, and swc compile one file at a time and can't tell whether User is a type or a value — so they can't safely know whether to drop the import. If a file only re-exports something that turns out to be a type, a value-style export { User } would emit a broken runtime reference. Marking it export type { User } (or import type) tells every tool, unambiguously, that it's erasable.

The modern setting verbatimModuleSyntax takes this further: it emits imports/exports exactly as written and errors on any value import that's used only as a type — nudging you to add type yourself rather than relying on invisible elision.