← Back to blog

It Took Us Four Weeks to Fix 2,800 Strict-Mode Errors: Here's What I'd Do Differently

By Ian, founder of CodeLazr · Updated 2026-09-14

I built CodeLazr because of one project that soured me on doing this by hand. We flipped on strict mode for an aging TypeScript repo expecting a weekend of cleanup. We got 2,800 errors. Four weeks later, I'd fixed most of them myself, one file at a time, and I was done doing that ever again.

Here's what actually causes a mess like that, and the pipeline I built afterward so it doesn't happen twice.


How You End Up With 2,800 Errors

Nobody sits down and decides to write bad TypeScript. It happens one deadline at a time. Someone hits a generic that's genuinely annoying to type correctly. They don't have twenty minutes to do it right. So they do this instead:

// The shortcut that starts the whole problem
function parseApiResponse(response: any): UserProfile {
    return {
        id: response.userId,
        name: response.fullName ?? "Unknown"
    };
}

Fine on its own. The problem is it never stays on its own. I found variations of that same shortcut copy-pasted into dozens of other files by the time I went looking. The compiler had effectively stopped watching. Nobody noticed until the backend renamed a field and something broke quietly, in production, at a bad hour.

It wasn't just any casts, either. We had dead exports nobody had touched in years. Barrel files were bloated enough to visibly slow our incremental builds. Components juggled six or seven independent boolean flags instead of one clean state type. That created "impossible" states that happened anyway, regularly.


Why Turning On Strict Mode Wasn't the Fix by Itself

We already had ESLint running. It does its job by flagging a violation and leaving the fixing to you. That's exactly the part that doesn't scale. Flip on strict across an entire repo at once and you get thousands of errors dumped into one terminal with no way to prioritize any of them. Four weeks of manual triage taught me why most teams just never turn strict mode on for old code. The upfront cost feels impossible to justify, even while the debt keeps compounding in the meantime.

What actually changed things for us was pairing the TypeScript Docs config options with a model that could read a flagged error in context and generate the real fix. We routed this through free models instead of paying per call to one provider for every single error in a 2,800-error backlog. At that volume, cost per check stops being an afterthought.


What Runs Now on Every PR

Once we'd cleared the backlog, the goal was simple: never do that dig again. A few specific things get checked automatically now:

When a PR lands, the system reads the diff against these patterns and drafts the fix before a reviewer's even opened the tab.


How I'd Run This on a Fresh Repo

If I were starting over, in order:

  1. One strict flag at a time. Start with noImplicitAny in tsconfig.json. Don't try to fix everything day one. Suppress what you must, temporarily, but block anything new from adding to the pile.
  2. Automate the dead-code sweep immediately. Run something like Knip in CI from day one. Unused exports get caught right away instead of piling up for two years, like ours did.
  3. Stop hand-writing types that mirror your backend. Generate them from your OpenAPI spec, your GraphQL schema, your database layer (Prisma, Kysely, whatever you're on). Manual mirrors drift. Always, eventually.
  4. Run automated passes on legacy code instead of doing it by hand. This is the part that would've saved me three of those four weeks:
# Example of running an automated type-hardening pass
npx codelazr analyze --fix-implicit-any --target ./src/api

It reads the target directory, swaps unsafe casts for real inferred types or explicit interfaces, and runs the test suite against the result. This ensures you're not merging a "fix" that quietly changed behavior underneath you.


Where This Leaves You

Debt like this happens if you're shipping fast. That part isn't avoidable. What is avoidable is losing four weeks of a real person's time clearing it by hand. That is exactly what pushed me to build CodeLazr.com. Clean code was never about getting it right the first time. It's about having something watching continuously, so the backlog never gets back to 2,800.


Related reading