Modules, Declaration Files & tsconfig Deep Dive

0/5 in this phase0/21 across the roadmap

📖 Concept

Modules in TypeScript follow the ES Module standard (import/export). Understanding module resolution, declaration files, and tsconfig options is essential for production TypeScript.

Declaration files (.d.ts) describe the types for JavaScript code that doesn't have TypeScript types. They're how TypeScript understands npm packages written in JavaScript.

@types/ packages — The DefinitelyTyped repository provides community-maintained type declarations for thousands of JavaScript packages. Install with npm i -D @types/lodash.

Module augmentation lets you add types to existing modules — extending library types without modifying their source.

tsconfig.json is the central configuration for the TypeScript compiler. Key sections:

  • compilerOptions — How TS compiles your code
  • include/exclude — Which files to process
  • references — Project references for monorepos

Critical tsconfig options:

  • strict: true — Enables all strict checks (ALWAYS use this)
  • target — Which JS version to output (ES2022 is a safe modern default)
  • module / moduleResolution — How imports are resolved
  • paths — Custom import aliases (@/components)
  • noUncheckedIndexedAccess — Arrays/objects may return undefined

🏠 Real-world analogy: Declaration files are like user manuals for tools you didn't build. You don't have the blueprints (source code), but the manual (d.ts) tells you what buttons to press (API types). tsconfig.json is like the settings panel for your car — target speed, safety features, navigation mode.

💻 Code Example

codeTap to expand ⛶
1// ES Module syntax (TypeScript follows this standard)
2// math.ts
3export function add(a: number, b: number): number {
4 return a + b;
5}
6export const PI = 3.14159;
7export default class Calculator { /* ... */ }
8
9// app.ts
10// import Calculator, { add, PI } from "./math";
11
12// Type-only imports (erased at compile time)
13// import type { User } from "./types";
14// import { type User, createUser } from "./users";
15
16// Declaration files (.d.ts) — type definitions for JS code
17// utils.d.ts
18// declare function formatCurrency(amount: number, currency: string): string;
19// declare const API_URL: string;
20// declare module "untyped-lib" {
21// export function doSomething(input: string): number;
22// }
23
24// Module augmentation — extend existing types
25// Extending Express Request (common pattern)
26// declare module "express" {
27// interface Request {
28// user?: { id: string; role: string };
29// }
30// }
31
32// Global augmentation
33// declare global {
34// interface Window {
35// analytics: { track(event: string): void };
36// }
37// }
38
39// Path aliases (in tsconfig: "paths": { "@/*": ["./src/*"] })
40// import { UserService } from "@/services/user";
41// import { Button } from "@/components/Button";
42
43// Ambient modules — declare types for non-TS files
44// declare module "*.css" {
45// const classes: Record<string, string>;
46// export default classes;
47// }
48// declare module "*.svg" {
49// import { FC, SVGProps } from "react";
50// const SVG: FC<SVGProps<SVGSVGElement>>;
51// export default SVG;
52// }
53
54// Namespace (legacy — prefer ES modules)
55// namespace Utils {
56// export function log(msg: string) { console.log(msg); }
57// export function warn(msg: string) { console.warn(msg); }
58// }
59// Utils.log("hello");
60
61// tsconfig.json — production-grade configuration:
62// {
63// "compilerOptions": {
64// "target": "ES2022",
65// "module": "ESNext",
66// "moduleResolution": "bundler",
67// "strict": true,
68// "noUncheckedIndexedAccess": true,
69// "noUnusedLocals": true,
70// "noUnusedParameters": true,
71// "noFallthroughCasesInSwitch": true,
72// "forceConsistentCasingInFileNames": true,
73// "esModuleInterop": true,
74// "skipLibCheck": true,
75// "declaration": true,
76// "declarationMap": true,
77// "sourceMap": true,
78// "outDir": "./dist",
79// "rootDir": "./src",
80// "paths": { "@/*": ["./src/*"] }
81// },
82// "include": ["src/**/*"],
83// "exclude": ["node_modules", "dist"]
84// }
85
86// Example: tsconfig for a Next.js project:
87// "compilerOptions": {
88// "lib": ["dom", "dom.iterable", "esnext"],
89// "jsx": "preserve",
90// "incremental": true,
91// "plugins": [{ "name": "next" }]
92// }
93console.log("Modules and tsconfig are the backbone of any TS project.");

🏋️ Practice Exercise

Mini Exercise:

  1. Create a .d.ts declaration file for an imaginary JavaScript utility library
  2. Set up path aliases in tsconfig and use them in imports
  3. Use module augmentation to add a custom property to Express Request
  4. Create a tsconfig with strict: true and all recommended options
  5. Write ambient module declarations for .css and .svg imports

⚠️ Common Mistakes

  • Not installing @types/ packages for JavaScript libraries — TypeScript won't know the types; install @types/express, @types/node, etc.

  • Confusing module and moduleResolution in tsconfig — module is the output format; moduleResolution is how TS finds imported files

  • Using namespace in new code — namespaces are legacy; ES modules (import/export) are the standard way to organize code

  • Not enabling skipLibCheck: true — checking ALL declaration files in node_modules is slow and finds irrelevant errors

  • Forgetting that .d.ts files are type-only — they cannot contain any implementation, only type declarations

💼 Interview Questions

🎤 Mock Interview

Practice a live interview for Modules, Declaration Files & tsconfig Deep Dive