Turning on TypeScript strict mode in a legacy codebase
February 28, 2026
The starting point
You inherit a TypeScript project with strict: false in tsconfig. Types are loose, any is everywhere, and null checks don't exist. The code works, but every refactor is a gamble because the type system isn't catching real bugs. You want strict mode, but flipping the flag produces 2,000 errors.
Don't flip the flag
The worst approach is enabling strict: true and spending a week fixing everything. You'll rush through fixes, add type assertions to suppress errors, and introduce subtle bugs. The codebase gets noisier without getting safer.
The incremental path
Enable strict sub-flags one at a time. Start with noImplicitAny because it surfaces the most impactful issues: functions where TypeScript silently infers any and you lose all type safety. Fix these file by file, starting with the most imported modules. Each fix ripples type information to consumers.
Next, enable strictNullChecks. This is the hardest one. Every function that can return undefined now forces callers to handle it. But this is also where the most bugs hide. That crash in production where user.name was undefined? strictNullChecks would have caught it at compile time.
Then strictFunctionTypes, strictBindCallApply, and the rest. By this point most of the work is done.
The escape valve
Use // @ts-expect-error sparingly for genuinely complex cases you'll fix later. Track them. Unlike any, expect-error will break when the underlying issue is fixed, so it's self-cleaning. Never use // @ts-ignore, it suppresses errors permanently and silently.
The result
Strict mode doesn't make TypeScript slower to write. It makes it faster to refactor. Every function signature becomes documentation. Every null check is a deliberate decision. The type system starts working for you instead of just being there.