Skip to content
Modules: import/export
step 1/6

Reading — step 1 of 6

Learn

~2 min readClasses and Modules

TypeScript uses ES modules (the modern standard). Each file is its own module — names declared in it are private unless explicitly exported.

Named exports

// math.ts
export function add(a: number, b: number): number {
    return a + b;
}

export function multiply(a: number, b: number): number {
    return a * b;
}

export const PI = 3.14159;
// app.ts
import { add, multiply, PI } from './math';

console.log(add(3, 4));     // 7
console.log(PI);             // 3.14159

Default export — one per module

// user.ts
export default class User {
    constructor(public name: string) {}
}

// app.ts
import User from './user';   // no braces — picks the default

A module can have one default export AND multiple named exports.

Import variations

import { add } from './math';                  // single named
import { add, multiply } from './math';        // multiple
import { add as plus } from './math';          // rename
import * as math from './math';                 // entire module as namespace
import User from './user';                      // default
import User, { Role } from './user';           // default + named
import './side-effect';                         // run for side effects only

Re-exports — barrel files

// utils/index.ts
export { add, multiply } from './math';
export { format } from './format';
export * from './strings';

Then consumers:

import { add, format } from './utils';

Keeps imports clean across deep folder structures.

Type-only imports

For types that don't exist at runtime:

import type { User } from './user';
import { type Role, hasPermission } from './auth';

import type makes it explicit and helps the compiler erase the import in the JS output.

Tree-shaking — only what you use

Named exports support tree-shaking — bundlers can drop unused exports from the final bundle. Default exports usually don't tree-shake well. Prefer named exports for libraries.

Common mistakes

  • Mixing default and named import syntax: import { default as User } works but import User is cleaner.
  • Circular imports — A imports B, B imports A. May silently produce undefined values. Refactor to break the cycle.
  • Forgetting import type for types — small inefficiency in some setups; cleaner anyway.
  • Using namespace module {} — old TS syntax. Use ES modules instead.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…