Modules, Config, and Tooling

Types are only half of TypeScript; the other half is the machinery that compiles, configures, and connects your code to the vast JavaScript ecosystem. ES modules organize code, `tsconfig.json` controls how strictly the compiler checks it, and declaration files let typed and untyped code interoperate. Understanding this layer is what turns a working `.ts` file into a real, maintainable project.

We’ve covered the type system thoroughly. This post is about everything around it: how code is organized into modules, how you configure the compiler (and why strict is the setting that matters most), and how TypeScript integrates with plain JavaScript libraries through declaration files. This is the practical infrastructure of a TypeScript project.

Modules: organizing code

Modern TypeScript uses ES modules — the standard import/export syntax — to split code into files with explicit dependencies:

// user.ts
export interface User { id: number; name: string; }
export function greet(u: User) { return `Hi, ${u.name}`; }

// app.ts
import { User, greet } from "./user";

Each file is a module with its own scope; nothing is global unless exported and imported. TypeScript understands modules natively and type-checks across them — import a function and the compiler knows its signature, so a wrong-type argument three files away is caught. Prefer named exports (as above) over default exports in most cases: they’re refactor-friendly (rename propagates), autocomplete-friendly, and avoid the ambiguity of default-export naming. Modules are how a TypeScript codebase stays navigable and how the compiler builds its cross-file understanding.

tsconfig.json: the control panel

Every TypeScript project has a tsconfig.json that tells the compiler what to compile and how. The options that matter most:

A minimal, sane config:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "strict": true,
    "outDir": "dist",
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

The config is your project’s contract with the compiler; getting it right (especially strict) determines how much safety you actually get. Many teams extend a shared base config for consistency.

strict mode: turn it on

If you take one thing from this post: enable strict: true. It’s an umbrella that turns on a family of checks, and without it TypeScript is a shadow of itself. The most consequential members:

Starting a new project without strict is choosing a weaker language for no reason. For an existing untyped codebase, you enable it incrementally (file by file, or flag by flag) as part of migration — but strict is the destination. Everything about TypeScript’s value proposition assumes it’s on.

Declaration files: bridging to JavaScript

The JavaScript ecosystem is enormous and mostly written in plain JS. Declaration files (.d.ts) are how TypeScript understands that untyped code: they contain only type information — signatures, no implementation — describing the shape of a JavaScript library so your typed code can call it safely.

// math.d.ts — types for a plain-JS math.js
export declare function add(a: number, b: number): number;

Two ways these show up:

Declaration files are also what your own library emits (tsc can generate .d.ts from your source) so consumers of your package get types. They’re the interface layer that lets the typed and untyped halves of the ecosystem interoperate — without them, TypeScript would be an island.

The build pipeline in practice

Because TypeScript compiles to JavaScript and erases types (post 1), a real project has a build step, and how you run it varies:

The practical setup for most projects: a fast bundler for builds, tsc --noEmit in CI to enforce type correctness, and strict on so that check has teeth. Understanding that transpiling (strip types) and type-checking (verify types) are separable explains why “it built fine but has type errors” is possible — and why you should gate merges on an actual type-check, not just a successful bundle.

Key takeaways

Further reading

Sources & References

Compiler configuration and strict mode