Skip to content

Modules and Imports

TypeScript uses standard ES module syntax (import/export) to split code across files, and additionally supports type-only imports β€” importing just a type or interface with no runtime footprint, which the compiler strips out entirely during compilation.

math.ts
export function add(a: number, b: number): number {
return a + b;
}
export interface Point { x: number; y: number; }
export default class Calculator { /* ... */ }
// app.ts
import Calculator, { add, Point } from "./math";
import type { Point } from "./math"; // type-only import -- erased at compile time
const p: Point = { x: 1, y: 2 };
const sum = add(2, 3);
// Re-exporting from a barrel file
export * from "./math";
export { add as addNumbers } from "./math";

Creating a circular dependency between modules (A imports from B, B imports from A) β€” this often works for types (which are erased and don’t have a runtime execution order) but can fail unpredictably for values, since one module may not have finished initializing when the other tries to use it.

a.ts
import { b } from "./b";
export const a = b + 1; // may be `undefined + 1` = NaN if b.ts hasn't run yet
// b.ts
import { a } from "./a";
export const b = a + 1; // circular! neither can safely initialize first
// Fix: extract the shared logic into a third module both can import from,
// or use `import type` if you only actually need the type, not the value
  1. What’s the difference between import { Point } and import type { Point }?

    Answerimport type tells the compiler this import is used only for type checking and can be completely erased from the compiled output β€” it has zero runtime footprint.
  2. Why can circular imports be risky for values but usually safe for types?

    AnswerTypes are erased at compile time and have no execution order to worry about; values are real runtime code, so a circular import can mean one module tries to use a value from another before it's finished initializing.
  3. What does export default let a consuming module do differently from a named export?

    AnswerIt can be imported without curly braces and under any name the importer chooses: import AnyNameYouWant from "./module", versus named exports which must match the exported name (or be explicitly aliased with as).