tsconfig, strict & Declarations
TypeScript is a compiler as much as a language. Its configuration, strictness flags, and declaration files determine how much safety you actually get.
tsconfig.json & strict Mode
tsconfig.json configures the compiler. The single most important setting is "strict": true, which turns on the full suite of type-safety checks. Without it, TypeScript is far more permissive than most people expect.
{
"compilerOptions": {
"target": "ES2022", // JS version to emit
"module": "ESNext", // module system
"strict": true, // enable all strict checks (do this)
"noUncheckedIndexedAccess": true, // arr[i] is T | undefined
"esModuleInterop": true,
"outDir": "./dist",
"skipLibCheck": true
},
"include": ["src/**/*"]
}
strict: true bundles strictNullChecks, noImplicitAny, strictFunctionTypes, and more. It's the difference between "types as documentation" and "types that actually catch bugs". Always start a project with it on.Modules & the Compile Pipeline
TypeScript uses ES module import/export, plus a type-only import form. The compiler (tsc) type-checks and emits JavaScript; in most projects a bundler (Vite, esbuild) handles the actual build for speed.
// value + type imports import { createUser } from "./users"; import type { User } from "./types"; // erased entirely at build export function greet(u: User) { return `Hi ${u.name}`; } # compile the whole project per tsconfig.json # tsc # type-check only, emit nothing (great for CI) # tsc --noEmit
import type makes it explicit that an import is only a type and will be stripped from the output. It avoids accidental runtime dependencies and can speed up builds. Pair with "verbatimModuleSyntax" for strict enforcement.Declaration Files (.d.ts)
A declaration file (.d.ts) describes the types of JavaScript code without any implementation. It's how untyped JS libraries get TypeScript support, and how your compiled library ships its types to consumers.
// describes the shape of a JS module — no implementation declare function add(a: number, b: number): number; declare const PI: number; export { add, PI };
Most popular libraries ship their own types or have community types on DefinitelyTyped, installed via @types/* packages.
.d.ts files in the package itself.npm i -D @types/node..d.ts for your own library so consumers get full typing.@types/x, or if none exists, add a declare module "x"; stub. Never reach for // @ts-ignore as a first resort.