Lesson 12 of 13
Modules, Declaration Files & tsconfig
Learn how tsconfig.json controls which files the checks, how strict it is and what JavaScript it outputs. Many confusing build problems come down to these settings.
{
"compilerOptions": {
"target": "ES2022", // JS version to emit
"module": "ESNext", // module syntax to emit
"moduleResolution": "bundler", // how imports are resolved (use "node16" for Node)
"lib": ["ES2022", "DOM"], // built-in APIs available
"strict": true, // turn this on. All of it. Day one.
"noUncheckedIndexedAccess": true,// arr[0] is T | undefined — catches real bugs
"noImplicitOverride": true,
"exactOptionalPropertyTypes": true,
"outDir": "dist",
"rootDir": "src",
"declaration": true, // emit .d.ts files for library consumers
"sourceMap": true,
"esModuleInterop": true,
"skipLibCheck": true, // do not type-check node_modules .d.ts files
"forceConsistentCasingInFileNames": true,
"paths": { "@/*": ["./src/*"] } // import { x } from "@/utils"
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}// Import and export forms
export const VERSION = '1.0.0' // named export
export function parse(input: string) { /* */ } // named export
export default class Client {} // default export (one per file)
export type { User } from './types' // type-only re-export
export * from './helpers' // re-export everything
// Consuming
import Client, { VERSION, parse } from './client'
import type { User } from './types' // erased at compile time
import { type Config, loadConfig } from './config' // inline type modifier
// "import type" matters: it guarantees the import disappears from the output,
// so importing a type never pulls a runtime module into your bundle.
// Dynamic import — code splitting, loads only when the branch runs
async function heavyWork() {
const { default: chart } = await import('./chart-library')
return chart.render()
}
// Declaration files (.d.ts) describe JavaScript that has no types.
// types/legacy-lib.d.ts
declare module 'legacy-lib' {
export interface Options { retries?: number }
export function connect(url: string, options?: Options): Promise<void>
export default function init(): void
}
// Augmenting an existing module's types
declare module 'express' {
interface Request {
user?: { id: number; role: 'admin' | 'user' } // your auth middleware adds this
}
}
// Global declarations — non-code assets and globals
declare global {
interface Window { analytics?: { track(event: string): void } }
namespace NodeJS {
interface ProcessEnv {
DATABASE_URL: string
NODE_ENV: 'development' | 'production' | 'test'
}
}
}
declare module '*.svg' {
const content: string
export default content
}
export {} // makes this file a module so "declare global" is legal
Finished reading?Mark it done to track your progress.
Tip: use the ← and → keys to move between lessons.