Skip to content
matthewcm.dev

    ↑ ↓ move · ↵ open · tab scopeopen graph →

    Driving a TypeScript Codebase to Zero Errors

    Case study — taking a large React codebase from a long backlog of TypeScript errors to zero with months of small, non-functional merge requests, so the build could finally enforce types.

    Growingcase studytended planted 2 min read
    On this page

    Context

    A large React front end for an enterprise platform had been migrated to TypeScript in name. The files were .tsx, but the compiler reported a long backlog of errors, so type checking was switched off in the build. New use cases were about to land on top of it.

    Problem

    With type errors tolerated, types stopped meaning anything. Nobody could tell a new error from the existing noise, so regressions that the compiler would have caught reached runtime. Every developer had learnt to ignore the red squiggles. And a “fix all the types” ticket was never going to be prioritised over features.

    What I did

    • Made it a background habit, not a project. Over several months I shipped a steady stream of small, non-functional merge requests, each fixing one folder or one category of error. Each was easy to review, impossible to break much with, and merged within a day.
    • Fixed causes, not symptoms. Where the same error appeared fifty times, the fix was usually one wrong type at a boundary, such as an API response or a shared helper. Typing the data layer properly (API Modelling) cleared whole swathes at once.
    • Refused to cheat. No blanket any, no @ts-ignore carpet. Where a proper signature needed more context than I had, I left an explicit, searchable unknown cast and flagged it for follow-up, rather than hiding it.
    • Locked in progress. Lint rules stopped new errors creeping into folders already cleaned, so the count could only go down.
    • Turned enforcement on at zero. Once the count reached zero, type checking became part of the build. From then on a type error failed the pipeline.

    Outcome

    Zero TypeScript errors, and build-time type checking switched on for good. New code got real compiler feedback, reviewers stopped arguing about types the compiler could settle, and the remaining loose casts were a short, visible list instead of an invisible swamp.

    What I’d do again

    • Small and steady beats heroic. It’s progressive overload for a codebase. No big-bang rewrite, just a little more load each week, and it never blocked feature work.
    • Ratchet, don’t promise. A rule that prevents regressions is worth more than a plan to fix everything.
    • Make the end state enforceable. The goal wasn’t “fewer errors”, it was “the build enforces types”. That’s a finish line everyone understands.

    What I’d do differently

    Turn on strictness per folder from the start (with a project-references or per-directory config), so cleaned areas got enforcement immediately rather than waiting for the whole codebase to hit zero.

    Shift Left Testing · Building a Low-Code BPMN Workflow Platform · SOLID React

    • #typescript
    • #tech-debt
    • #incremental-migration
    • #code-quality
    • #case-study

    ↪ Links to (5)