When a client came to us with a 100,000-line JavaScript monolith and asked us to "add types," we knew this wasn't a weekend project. Six months later, we had a fully typed codebase with zero production regressions during the migration. Here's exactly how we did it.
Why Migrate at All?
The codebase had grown over four years with a rotating cast of developers. Bugs from type mismatches were costing the team 15+ hours per sprint. Onboarding new developers took weeks because no one trusted the code. TypeScript wasn't a nice-to-have — it was survival.
The Incremental Strategy
We never did a "big bang" migration. Instead, we followed this approach:
Phase 1: Foundation (Week 1-2)
- Added
tsconfig.jsonwithallowJs: trueandstrict: false - Renamed entry points from
.jsto.ts - Set up CI to run
tsc --noEmitalongside existing tests - Created shared type definitions for API responses and domain models
Phase 2: Outside-In (Weeks 3-12)
We started at the edges — API client functions, utility libraries, and React component props. These files have the clearest contracts and fewest dependencies. Each PR converted 5-15 files and was reviewed same-day.
Phase 3: The Core (Weeks 13-20)
Business logic and state management were the hardest. We used @ts-expect-error sparingly as a migration marker, tracking every instance in a dashboard. Each one was a TODO with a deadline.
Phase 4: Strict Mode (Weeks 21-24)
Once all files were .ts/.tsx, we enabled strict flags one at a time: strictNullChecks, noImplicitAny, strictFunctionTypes. Each flag surfaced a new class of hidden bugs.
Tooling That Saved Us
- ts-migrate — Automated the initial
.js → .tsrename and added baseline types - knip — Found dead code we could delete instead of typing
- TypeScript error dashboard — Custom script counting remaining errors by strict flag, giving us a progress metric
Results
- 73% reduction in type-related production bugs
- 40% faster developer onboarding
- Zero downtime during the entire migration
- Developer satisfaction scores jumped from 6.2 to 8.7 out of 10
Thinking about migrating to TypeScript? We've done it before and we'd love to help.