TypeScript Module System

The module system is the foundation of modern TypeScript development.

TypeScript fully supports ES Module syntax and provides rich module resolution strategies.

Through the module system, code can be split into reusable units, enabling code organization and reuse.


SVG Diagram: Module Export/Import Background Title Module Export/Import Flow user.ts Module user.ts export const name = "Alice" export class User { ... } export interface Config { ... Arrow import main.ts Module main.ts import { name, User } from "./user"; import User from "./user" Arrow use Runtime Output JavaScript Execute Code Lower Section: Export Types Export/Import Methods Method 1 Named Export/Import Method 2 Default Export/Import Method 3 Re-export Method 4 Dynamic Import Arrow Marker

Why Do We Need a Module System

As project scale grows, the amount of code increases.

Distributing code across multiple files and organizing it through modules improves code maintainability and reusability.

The module system gives each file its own scope, preventing global variable pollution.

Concept Explanation:A module is a TypeScript file that contains export and import statements. Content is exported via export and imported via import.


Module Export

Use the export keyword to export variables, functions, classes, interfaces, etc. for use by other modules.

user.ts Module

// Export variable
export var name = "Alice";
export const age = 25;

// Export function
export function greet(message: string): string {
    return "Hello, " + message;
}

// Export class
export class User {
    // Constructor parameter properties
    constructor(public name: string) {}

    // Self-introduction method
    introduce(): string {
        return "I am " + this.name;
    }
}

// Export interface (interfaces disappear after compilation; only used for type checking)
export interface Config {
    // Configure host
    host: string;
    // Configure port
    port: number;
}

// Batch export: rename exports
export { name as userName, age as userAge };

Note:Interfaces and types do not generate actual code in compiled JavaScript; they are only used for TypeScript type checking.


Module Import

Use the import keyword to import exported content from other modules.

main.ts Importing Module

// Named import: import specific content from a module
import { name, age, greet } from "./user";

// Default import: import a module's default export
import User from "./user";

// Import all: put all module exports into an object
import * as UserModule from "./user";

// Rename import: avoid naming conflicts
import { greet as sayHello } from "./user";

// Use imported content
console.log(greet("World"));
console.log(sayHello("TypeScript"));

Output:

Hello, World
Hello, TypeScript

Path Explanation:Import paths can be relative paths (e.g.,./user) or absolute paths (e.g.,@/utils)。


Default Export

Each module can have one default export.

Default exports do not require curly braces when importing and can be given any name.

math.ts Module

// Default export: a module can only have one default export
export default function add(a: number, b: number): number {
    return a + b;
}

// Can be mixed with other exports
export function multiply(a: number, b: number): number {
    return a * b;
}

main.ts Import

// Import default export: can use any name
import add from "./math";

// Import named export: requires curly braces
import { multiply } from "./math";

console.log("Addition: " + add(2, 3));
console.log("Multiplication: " + multiply(4, 5));

Output:

加法: 5
乘法: 20

Recommendation:Use default exports for main export content such as utility functions and classes; use named exports for helper functions, interfaces, etc.


Re-export

Re-export is used to aggregate content from multiple modules or expose one module's exports to another module.

index.ts Aggregating Module

// Re-export specific content from other modules
export { name, age } from "./user";

// Re-export default export (requires renaming)
export { default as User } from "./user";

// Re-export all content
export * from "./math";

Use Cases:Use index.ts as an entry file to centrally export child module content for unified imports.


Module Resolution Strategies

TypeScript provides multiple module resolution strategies for locating imported modules.

This can be configured in tsconfig.json.

tsconfig.json Configuration

{
    "compilerOptions": {
        // Node resolution strategy
        // Follows Node.js module resolution rules
        "moduleResolution": "node",

        // Classic resolution strategy
        // Strategy used by early versions of TypeScript
        "moduleResolution": "classic",

        // base URL: sets the base path
        // All non-relative path imports are resolved based on this path
        "baseUrl": "./src",

        // Path mapping: sets aliases for import paths
        "paths": {
            // Imports starting with @ map to the src directory
            "@/*": ["./*"],
            // Imports starting with @components map to the components directory
            "@components/*": ["./components/*"]
        }
    }
}

Configuration Recommendation:For new projects, the Node resolution strategy is recommended as it is currently the most commonly used approach.


Dynamic Import

Dynamic Import uses the import() syntax to load modules on demand at runtime.

This is very useful for code splitting and lazy loading.

Example

// Dynamic import - lazy loading
// import() returns a Promise
async function loadMath() {
    // Dynamically import module; it is only loaded when execution reaches this point
    var math = await import("./math");

    // math.default is the default exported function
    console.log("Dynamic Addition: " + math.default(1, 2));
}

// Call the lazy-loaded function
loadMath();

// Conditional import: dynamically load different modules based on conditions
async function loadFeature(enable: boolean) {
    if (enable) {
        // Only load the module when the condition is met
        var feature = await import("./feature");
        feature.run();
    }
}

// Load based on condition
loadFeature(true);

Output:

动态加法: 3

Performance Optimization:Dynamic imports enable code splitting, loading additional code only when needed, reducing initial load time.


Notes

  • Relative Paths:Use relative paths to import local modules (./, ../)
  • Module Extensions:TypeScript automatically handles extensions during compilation
  • Default vs Named:One default export per module, multiple named exports
  • esModuleInterop:Enabling this option makes it easier to import CommonJS modules

Best Practices:Keep import paths consistent, use path aliases to simplify long paths, and establish a clear module organization structure.


Summary

The module system is the core of TypeScript project organization.

  • export:Export variables, functions, classes, interfaces
  • import:Import exported content
  • Default Export:One per module, flexible to use
  • Re-export:Aggregate modules, create entry files
  • Dynamic Import:Lazy loading, performance optimization
  • Module Resolution:Configure path aliases and resolution strategies

Recommendation:Organize module structure reasonably, use path aliases to simplify imports, and establish clear export/import conventions.

Other Extensions