tsconfig, Deep
Start from strict
Section titled “Start from strict”tsconfig.json has dozens of options, but a handful decide whether TypeScript is actually protecting you. The single most important one is strict. It is not one check — it is a bundle that turns on a family of flags at once, and every one of them catches real bugs.
{ "compilerOptions": { "strict": true, "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "lib": ["ES2022"], "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true, "noImplicitOverride": true, "verbatimModuleSyntax": true }}Turn strict on from day one. Adopting it later, on a large codebase, means fixing hundreds of errors at once — far harder than never letting them accumulate.
What strict actually turns on
Section titled “What strict actually turns on”strict: true is shorthand for this whole family:
Flag (inside strict) | What it catches |
|---|---|
strictNullChecks | null and undefined are no longer silently in every type — the biggest win |
noImplicitAny | A value that would fall back to any becomes an error you must resolve |
strictFunctionTypes | Function parameters are checked contravariantly — unsafe callbacks are caught |
strictBindCallApply | bind, call, and apply are type-checked against the function signature |
strictPropertyInitialization | Class fields must be assigned in the constructor (or marked optional) |
useUnknownInCatchVariables | catch (e) gives you unknown, not any, forcing you to narrow |
alwaysStrict | Emits "use strict" and parses in strict mode |
The headline is strictNullChecks. Without it, string secretly includes null and undefined, and the compiler cannot warn you about the single most common runtime crash in JavaScript. With it, null and undefined are their own types that you must handle deliberately.
target, module, and lib
Section titled “target, module, and lib”Three options describe the world your code runs in:
target— which JavaScript versiontscemits.ES2022is a safe modern default; a lower target down-levels newer syntax into older equivalents.module— the module format of the output (NodeNext,ESNext,CommonJS, …). This should match how your code is actually loaded.lib— which built-in type declarations are available (for example,DOMfor browser globals,ES2022for newer runtime methods). If you usestructuredCloneorArray.prototype.at, yourlibmust include a version that declares them.
Strict-adjacent flags worth adding
Section titled “Strict-adjacent flags worth adding”strict is the floor, not the ceiling. Two more flags catch bugs that strict alone misses:
// noUncheckedIndexedAccess: trueconst arr = [1, 2, 3];const x = arr[10]; // type is now `number | undefined`, not `number`x.toFixed(); // ❌ Object is possibly 'undefined' — exactly the bug you want caughtnoUncheckedIndexedAccess— indexing an array or record can returnundefined(index 10 of a 3-element array does), so the type reflects that. Enormously effective against out-of-bounds bugs.exactOptionalPropertyTypes— distinguishes a property set toundefinedfrom a property that is absent, so an optionalname?: stringno longer silently acceptsname: undefined.