INTRO
Flipping `strict` overnight on a MERN repo breaks hundreds of files. I tighten from the outside in: new code strict, old code behind boundaries, and compiler flags staged with `// @ts-expect-error` tickets attached to real fixes.
Type boundaries first
HTTP handlers: validate with Zod and infer types. Database models: generate types from schema or define interfaces for documents you return to the client.
Untyped `any` at legacy core is tolerable short-term if the API surface is honest.
Enable flags incrementally
Order that usually works: `strictNullChecks`, `noImplicitAny`, `strict`, then `noUncheckedIndexedAccess` if the team wants pain for gain.
CI must run `tsc --noEmit`; eslint alone misses types.
code-snippet.json
{
"compilerOptions": {
"strict": true,
"skipLibCheck": true
},
"include": ["src"]
}Let tests catch behavior; types catch shape
Types do not replace integration tests for auth and payments. They reduce dumb null crashes and wrong field names - which still matter.
KEY TAKEAWAYS
“Type the HTTP and DB boundaries before inner legacy utilities.”
- 02
Enable strict flags in stages; fix or ticket each `expect-error`.
- 03
Run `tsc` in CI alongside tests.
CONCLUSION
Closing thought
Strict TypeScript is a migration, not a switch. Progress beats perfection - tighten where new code and public surfaces live. Ready to talk scope? Use Contact — or browse Services for fit.
CONTINUE
Related pages
UP NEXT
Integration Testing Node.js APIs with Supertest
How I structure Jest + Supertest suites for Express apps: test database, seeding, auth headers, and what not to mock if you want confidence.
Read next article