Export Types From a Module Without Runtime Code
Compare import type, the inline type keyword and a plain import, and see which ones leave code in the compiled file. After this, a types-only import cannot load a module with side effects.
A types file should cost nothing when the program runs. Often it does cost something: an import that is only there for a type can still make Node load the whole module behind it, side effects included. This page shows the three ways to write a type import, what each one leaves in the compiled output, and how to prove it. The course lesson on modules introduces import type. This is the practical follow-up, with re-exports.
Step 1: a module with a side effect
export type User = { id: number; name: string };
export function makeUser(id: number, name: string): User {
return { id, name };
}
console.log("user module loaded");
The last line stands in for anything a real module does when it loads: open a connection, read a file, register a handler. A file that only needs the User type should never trigger it.
Step 2: import type leaves nothing behind
import type { User } from "./user.js";
const ana: User = { id: 1, name: "Ana" };
console.log(ana.name);
Ana
Only Ana is printed. The line user module loaded never appears, because the compiled app.js has no import at all.
cat app.js
const ana = { id: 1, name: "Ana" };
console.log(ana.name);
export {};
Step 3: the inline type keyword still loads the module
You can also mark a single name inside braces. That reads well, and it is the form many style guides prefer. With verbatimModuleSyntax turned on, it behaves differently from import type.
import { type User } from "./user.js";
const ana: User = { id: 1, name: "Ana" };
console.log(ana.name);
user module loaded
Ana
The module loaded. The compiled file keeps an empty import, import {} from "./user.js", because under verbatimModuleSyntax the compiler keeps every import statement exactly as you wrote it and only removes the names marked type. An import with nothing left in the braces still runs the module.
cat app.js
import {} from "./user.js";
const ana = { id: 1, name: "Ana" };
console.log(ana.name);
If the file only needs types, write import type { User } from "./user.js", and the whole line goes.
Step 4: a plain import is an error under the strict flag
import { User } from "./user.js";
const ana: User = { id: 1, name: "Ana" };
console.log(ana.name);
plain.ts(1,10): error TS1484: 'User' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
This is the setting that tsc --init writes, and it exists to stop that guess. Without the flag, TypeScript decides on its own that User is only a type and drops the import. Other tools that compile one file at a time, such as esbuild or Babel, cannot always make that decision, which is why the explicit form is safer.
Step 5: re-export types as types
A barrel file, the index.ts that re-exports from several files, should follow the same rule.
export type { User } from "./user.js";
export { makeUser } from "./user.js";
npx tsc index.ts
cat index.js
export { makeUser } from "./user.js";
The export type line is gone from the output. Only the value export remains. A barrel that has nothing but export type lines compiles to an empty module, and no file behind it loads.
⚠ Warning: A plain export * from "./user.js" re-exports values too, so importing the barrel always loads user.js, side effect included. If a barrel must stay free of side effects, list the type exports with export type and keep the value exports in a separate file.
Common mistakes
- Using
import { type X }when the whole import is only types. The braces stay, and the module still loads. - Using
export *on files that run code when they load. - Keeping types and constants in the same file and expecting the constants to be erased. A constant is a value.
Related course: TypeScript Intermediate.
About
Compare import type, the inline type keyword and a plain import, and see which ones leave code in the compiled file. After this, a types-only import cannot load a module with side effects.
- Responsible
- Mary Q
- Last Update
- 10/11/2026
- Reading Time
- 4 min
Reviews
Sign in to write a reviewComments (0)
Sign in to commentNo comments yet.