AI Reading
Quick summary of this article
Modules in TypeScript help developers organize, reuse, and maintain code by keeping related functionality in separate files. They prevent global scope pollution, make dependencies explicit, and allow sharing code across projects. This guide covers the two main export styles—named exports for multiple values per file and default exports for a single primary value—plus advanced patterns like renaming, re-exporting, and namespace imports.
- Named exports allow exporting multiple variables, functions, or classes per file, and are imported with curly braces (e.g.,
import { PI, sum } from './utils'). - Default exports provide one primary value per file, imported without braces (e.g.,
import Logger from './Logger'), and are best used sparingly for main classes or functions. - Renaming imports with the
askeyword avoids naming collisions, while re-exporting through barrel files (e.g.,export { default as add } from './add') simplifies import paths in large projects. - Namespace imports (
import * as Utils from './utils') bundle all exports into one object, useful for grouping related functionality. - Best practices include preferring named exports for consistent naming and tree-shaking, avoiding circular dependencies, and configuring
tsconfig.jsonwith"module": "ES2015"or higher for modern projects.
Modules are essential for organizing, reusing, and maintaining code in TypeScript. They help encapsulate functionality, avoid global scope pollution, and enable efficient dependency management. Let’s explore named exports, default exports, and other key concepts with practical examples.
Why Use Modules?
- Encapsulation: Keep variables/functions private unless explicitly exported.
- Reusability: Share code across files.
- Structure: Break down complex apps into manageable pieces.
- Dependency Management: Explicitly declare dependencies.
Key Concepts
TypeScript supports two module systems:
- ES Modules (Modern:
import/export) - CommonJS (Node.js:
require/module.exports).
This guide focuses on ES Modules.
1. Named Exports (Multiple Exports per File)
Export individual values (variables, functions, classes) by name.
Syntax: export { name1, name2, ... }
Example:
// 📁 utils.ts
export const PI = 3.14; // Named export (variable)
export function sum(a: number, b: number): number { // Named export (function)
return a + b;
}
class Calculator { // Named export (class)
static multiply(a: number, b: number): number {
return a * b;
}
}
export { Calculator }; // Export declared class
Import Named Exports:
// 📁 app.ts
import { PI, sum, Calculator } from './utils';
console.log(PI); // 3.14
console.log(sum(2, 3)); // 5
console.log(Calculator.multiply(4, 5)); // 20
2. Default Export (Single Export per File)
Export one primary value (e.g., a function, class, or object).
Syntax: export default value;
Example:
// 📁 Logger.ts
export default class Logger { // Default export (class)
static log(message: string): void {
console.log(`[LOG] ${message}`);
}
}
// ❌ Avoid multiple default exports in one file!
Import Default Exports:
// 📁 app.ts
import Logger from './Logger'; // No braces needed!
Logger.log("Hello Modules!"); // [LOG] Hello Modules!
3. Combining Named and Default Exports
Mix both in one module:
// 📁 math.ts
export const PI = 3.14; // Named export
export default function add(a: number, b: number): number { // Default export
return a + b;
}
Import Both:
// 📁 app.ts
import add, { PI } from './math'; // Default + named
console.log(add(PI, 10)); // 13.14
4. Renaming Exports/Imports
Avoid naming collisions with aliases:
// 📁 app.ts
import { sum as addNumbers } from './utils'; // Rename named export
import Logger as MyLogger from './Logger'; // Rename default export
MyLogger.log(addNumbers(1, 2)); // [LOG] 3
5. Re-exporting (Barrel Files)
Aggregate exports from multiple files:
// 📁 math/index.ts
export { default as add } from './add'; // Re-export default
export { PI } from './constants'; // Re-export named
Usage:
// 📁 app.ts
import { add, PI } from './math'; // Clean import path
6. Import Everything as a Namespace
Bundle all exports into a single namespace object:
// 📁 app.ts
import * as Utils from './utils';
console.log(Utils.PI); // 3.14
console.log(Utils.sum(1, 2)); // 3
Best Practices
- Prefer Named Exports:
- Ensures consistent naming across imports.
- Facilitates tree-shaking (dead code elimination).
- Use Default Exports Sparingly:
- Ideal for primary classes/functions (e.g.,
React.Component).
- Ideal for primary classes/functions (e.g.,
- Barrel Files:
- Simplify imports in large projects (e.g.,
import { User, Post } from './models').
- Simplify imports in large projects (e.g.,
Common Pitfalls
- Default vs. Named Confusion:
// ❌ Error: Named import for default export import { Logger } from './Logger'; // Incorrect! // ✅ Correct import Logger from './Logger'; - Circular Dependencies: Avoid modules importing each other (e.g.,
A → B → A).
Conclusion
Modules are the backbone of scalable TypeScript applications:
- Named Exports: For multiple values.
- Default Exports: For a module’s primary functionality.
- Re-exports: Simplify dependency graphs.
By mastering these patterns, you’ll write cleaner, more maintainable code. 🚀
Pro Tip: Configure tsconfig.json with "module": "ES2015" (or higher) for modern projects!
