Technology · TypeScript
TypeScript Modules
Learn how to organize TypeScript code using ES modules, named exports, and default exports.
TL;DR
- 01Use export and import to share code between files.
- 02Choose named exports for multiple values per module.
- 03Use type-only imports to keep runtime bundles small.
Named Exports
- Add the
exportkeyword in front of any declaration to share it.// utils.ts export const PI = 3.14159; export function double(n: number) { return n * 2; } - Import named exports using curly braces and the exact names.
import { PI, double } from "./utils"; - Rename imports inline with the
askeyword to avoid conflicts.import { double as multiplyByTwo } from "./utils"; - Export multiple values from one file for related helpers and constants.
- This is the most common style in modern TypeScript codebases.
Default Exports
- Use
export defaultto mark one main export per file.// logger.ts export default function log(msg: string) { console.log(msg); } - Import the default with any name you choose, without curly braces.
import log from "./logger"; - A file can have one default export and any number of named exports.
- Default exports lose the original name during import, which hurts refactoring.
- Many style guides recommend named exports over defaults for that reason.
Re-exports
- Re-export from another file to build a barrel that groups related modules.
// index.ts export { double, PI } from "./utils"; export { default as log } from "./logger"; - Use
export * fromto re-export every named export from a module.export * from "./utils"; - Barrels make imports cleaner across the rest of your codebase.
- They can also hurt tree-shaking, so use them carefully in large projects.
- Place barrel files at the root of folders for predictable import paths.
Type-only Imports
- Use the
typekeyword to import only types, not runtime values.import type { User } from "./types"; - Type-only imports are erased during compilation for smaller bundles.
- Mix value and type imports in one statement using the inline
typekeyword.import { type User, getUser } from "./api"; - Use
export typeto re-export types without runtime code.export type { User } from "./types"; - This is especially helpful when working with bundlers and isolated modules.
Module Resolution
- Use relative paths like
./utilsfor files inside your project. - Use bare specifiers like
reactfor packages installed innode_modules. - Configure path aliases in
tsconfig.jsonto shorten deep import paths.import { Button } from "@/components/Button"; - The
moduleResolutionsetting controls how the compiler finds modules. - Use
"bundler"mode in modern projects that rely on tools like Vite or Webpack.
Tip: Prefer named exports over default exports, since they keep import names consistent and make refactoring much safer.
Warning: Path aliases require both
tsconfig.jsonand your bundler to agree, or imports will work in the IDE but fail at runtime.