TypeScript Modules and Imports

A module is a TypeScript file that keeps its code private by default. Variables, functions, classes, and types inside a module are not visible to other files unless they are explicitly exported. Another file gains access to them by importing them. This system organizes large codebases into focused, manageable files and prevents naming conflicts between different parts of an application.

Why Modules?

  Without modules — everything in one file:
  +----------------------------------------------+
  | app.ts                                       |
  | function validateEmail() { ... }             |
  | function calculateTax() { ... }              |
  | function renderPage() { ... }                |
  | class UserManager { ... }                    |
  | class ProductManager { ... }                 |
  +----------------------------------------------+
  Hard to navigate, maintain, and reuse.

  With modules — each file has one responsibility:
  +-----------------+    +------------------+    +------------------+
  | utils/           |    | services/        |    | models/          |
  | validation.ts    |    | tax.ts           |    | user.ts          |
  | Exports:         |    | Exports:         |    | Exports:         |
  | validateEmail()  |    | calculateTax()   |    | class User       |
  +-----------------+    +------------------+    +------------------+
         |                      |                        |
         +------------ app.ts imports all ---+-----------+

Exporting from a Module

Named Exports

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

export function subtract(a: number, b: number): number {
    return a - b;
}

export const PI: number = 3.14159;

export type MathResult = {
    value: number;
    operation: string;
};

Export After Declaration

// utils.ts
function formatCurrency(amount: number, symbol: string = "₹"): string {
    return symbol + amount.toFixed(2);
}

function capitalize(text: string): string {
    return text.charAt(0).toUpperCase() + text.slice(1);
}

// Export multiple at the end
export { formatCurrency, capitalize };

Export with Rename

// helpers.ts
function calculateGST(amount: number): number {
    return amount * 0.18;
}

export { calculateGST as computeGST };
// Imported as: computeGST — original name stays private

Default Exports

Each module can have one default export. A default export represents the main item the module provides. It is imported without curly braces and can be given any name by the importer.

// logger.ts
export default class Logger {
    log(message: string): void {
        console.log("[LOG] " + new Date().toISOString() + ": " + message);
    }

    error(message: string): void {
        console.log("[ERROR] " + message);
    }
}

Importing a Module

Named Imports

// app.ts
import { add, subtract, PI } from "./math";

console.log(add(10, 5));       // 15
console.log(subtract(10, 5));  // 5
console.log(PI);               // 3.14159

Renamed Import

import { formatCurrency as format } from "./utils";

console.log(format(1999));   // ₹1999.00

Namespace Import (Import All)

import * as MathUtils from "./math";

console.log(MathUtils.add(4, 6));  // 10
console.log(MathUtils.PI);         // 3.14159

Default Import

import Logger from "./logger";          // Any name works for default import
import MyLogger from "./logger";        // Same module, different name — both valid

let log = new Logger();
log.log("App started");  // [LOG] 2025-03-21T...: App started

Mixed Import (Default + Named)

// config.ts
export default class AppConfig {
    appName: string = "eStudy247";
}

export const VERSION: string = "2.0.0";
export const ENVIRONMENT: string = "production";
// app.ts
import AppConfig, { VERSION, ENVIRONMENT } from "./config";

let config = new AppConfig();
console.log(config.appName + " v" + VERSION); // eStudy247 v2.0.0

Re-Exporting

A module can re-export items from another module, creating a single entry point (called a barrel file) for related exports.

  Without barrel:
  import { add }    from "./math/add";
  import { format } from "./utils/format";
  import Logger     from "./logging/logger";

  With barrel (index.ts re-exports everything):
  import { add, format, Logger } from "./index";
// index.ts — barrel file
export { add, subtract, PI }            from "./math";
export { formatCurrency, capitalize }   from "./utils";
export { default as Logger }            from "./logger";
export type { MathResult }              from "./math";

Type-Only Imports and Exports

TypeScript supports importing and exporting types specifically. Type-only imports are removed completely during compilation, resulting in smaller JavaScript output.

// types.ts
export type UserId = number | string;
export type CourseStatus = "draft" | "published" | "archived";

export interface CourseData {
    id: UserId;
    title: string;
    status: CourseStatus;
}
// app.ts
import type { UserId, CourseData } from "./types";
// These imports vanish in the compiled .js file

let id: UserId = 101;
let course: CourseData = { id: 101, title: "TypeScript", status: "published" };

Module File Structure

  Typical TypeScript Project Structure:
  src/
  ├── models/
  │   ├── user.ts           ← export interface User
  │   ├── course.ts         ← export interface Course
  │   └── index.ts          ← barrel: re-exports User, Course
  │
  ├── services/
  │   ├── userService.ts    ← export function getUser()
  │   ├── courseService.ts  ← export function getCourses()
  │   └── index.ts          ← barrel: re-exports all services
  │
  ├── utils/
  │   ├── format.ts         ← export function formatDate()
  │   └── validate.ts       ← export function validateEmail()
  │
  └── app.ts                ← main entry point

Module Resolution

Import PathMeaningExample
Relative pathRelative to current file./math, ../utils
Absolute pathFrom project root (with path mapping)@/utils/format
npm packageFrom node_moduleslodash, axios

Practical Example

// models/student.ts
export interface Student {
    studentId: number;
    name: string;
    email: string;
    grade: string;
}

export type StudentSummary = Pick<Student, "studentId" | "name" | "grade">;
// services/studentService.ts
import { Student, StudentSummary } from "../models/student";

const students: Student[] = [
    { studentId: 1, name: "Aarti", email: "aarti@mail.com", grade: "A" },
    { studentId: 2, name: "Bharat", email: "bharat@mail.com", grade: "B" },
    { studentId: 3, name: "Chitra", email: "chitra@mail.com", grade: "A+" }
];

export function getAllStudents(): Student[] {
    return students;
}

export function getSummaries(): StudentSummary[] {
    return students.map(({ studentId, name, grade }) => ({ studentId, name, grade }));
}
// app.ts
import { getAllStudents, getSummaries } from "./services/studentService";

let all = getAllStudents();
console.log("Total Students: " + all.length); // Total Students: 3

let summaries = getSummaries();
summaries.forEach(s => {
    console.log(s.studentId + ". " + s.name + " | " + s.grade);
});
// 1. Aarti | A
// 2. Bharat | B
// 3. Chitra | A+

Leave a Comment