TypeScript in strict mode: why and how
The turning point
I long left strict mode aside in my early TypeScript projects. The code compiled, everything seemed to work, so why bother with options that only add errors to fix? I changed my mind the day an unhandled `undefined` crashed a critical function in production, even though TypeScript had not raised any warnings at compile time.
What `strict: true` actually changes
This option doesn’t activate a single rule; it turns on a whole suite of checks at once. The two that really change daily work are:
- **`strictNullChecks`** — TypeScript forces you to explicitly handle `null` and `undefined` cases. No more accessing a property on an object that, in theory, “should never be empty.”
- **`noImplicitAny`** — every parameter or variable without an explicit type becomes an error instead of a silent `any`. It forces you to think about typing at the moment you write the code, not six months later while trying to understand a function you’ve forgotten.
Configuration
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"noUncheckedIndexedAccess": true
}
}I gladly add `noUncheckedIndexedAccess` on top of the standard strict settings: without it, TypeScript assumes that accessing an array (`arr[i]`) always returns a value, even out of bounds. With it, you must check before using the result.
Migrating an existing project without breaking everything
Turning on `strict` all at once in an old project often surfaces hundreds of errors and discourages you before you even start. What works better in practice:
1. Enable `strictNullChecks` alone first — it yields the most value with the least breakage. 2. Tackle files one by one rather than trying to fix everything at once, starting with the most-used modules: correct typing naturally propagates to the rest of the codebase. 3. Replace remaining `any`s with real types as you touch each file, not in a dedicated pass that never actually happens.
The real difference it makes
The real win isn’t in the number of bugs caught at compile time; it’s in the confidence you gain when modifying code you didn’t write yourself. A refactor that would have required a full manual review becomes one where the compiler immediately points out the broken spots.