{"post":{"slug":"typescript-strict-mode-guide-2026","title":"TypeScript strict mode in 2026: how to migrate an old codebase safely","excerpt":"Enabling strict mode on a 5-year-old TS codebase without burning a quarter. The flag-by-flag order, the auto-fixes that work, and what to skip.","category":"code","date":"February 4, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">L</span>egacy TypeScript codebases without strict mode are everywhere. The migration looks scary — thousands of errors light up the moment you flip the flag — but it's straightforward if you do it incrementally and use the AI tools that actually work in 2026. Here's the order, the tools, and what to skip.\n\n## What changed in 2026\n\n- **TypeScript 5.5** introduced inferred type predicates and other strict-mode-easing features.\n- **AI codemods (Claude / Cursor agents) handle the bulk of trivial fixes.** Time savings is 5-10x vs hand-edits.\n- **`expect-type` and `vitest`** make testing type-level changes easier.\n\n## The flag order\n\nDon't toggle `strict: true` and stare at 8,000 errors. Enable individual flags in this order:\n\n**1. `noImplicitAny`** — usually the easiest. Wherever TS can't infer, you must annotate. Auto-fixable about 80% of the time with AI codemods.\n\n**2. `strictNullChecks`** — the painful one. Now `string | null` and `string` are different types. Expect 50-70% of total migration work to be here. Worth it: this flag prevents the largest class of real production bugs.\n\n**3. `strictFunctionTypes`** — function-parameter contravariance. Usually a handful of errors, easy fixes.\n\n**4. `noImplicitReturns`** — every code path must return something explicit. Adds discipline; minor effort.\n\n**5. `strictBindCallApply`** — type-checks `.bind()`, `.call()`, `.apply()`. Trivial for most codebases.\n\n**6. `strictPropertyInitialization`** — class properties must be initialized. Usually requires `definite assignment assertion (!)` for fields set in `useEffect`-style patterns.\n\n## The AI-assisted migration workflow\n\nFor each flag:\n\n1. Enable the flag in `tsconfig.json`.\n2. Run `tsc --noEmit` and capture all errors to a file.\n3. Group errors by file.\n4. Pass error groups to Claude or Cursor with: \"Fix these TypeScript strict-mode errors. Don't change behavior. Mark anything ambiguous with a TODO.\"\n5. Run tests after each batch.\n6. Don't enable the next flag until all errors from the previous are resolved.\n\nThis pipeline gets you 80%+ auto-fix rate. The remaining 20% are the cases where the human (or a more careful AI pass) needs to actually decide what the code should do.\n\n## Block regressions in CI\n\nThe minute you start the migration, add `--noEmitOnError` in your build step or run `tsc --noEmit` in a required CI check. Otherwise, every PR while you're migrating will add fresh strict-mode violations. The check should be set per directory or per file pattern as you migrate, not all-at-once.\n\n## Comparison: migration approaches in 2026\n\n| Approach | Time (10k LOC) | Quality | Best for |\n| --- | --- | --- | --- |\n| Flag-by-flag, AI-assisted | 1-3 days | High | Most teams |\n| Big-bang, hand-fix | 2-4 weeks | Variable | Small codebases |\n| File-by-file with `// @ts-strict` | 4-8 weeks | High | Massive monorepos |\n| Hire a contractor | 1-2 weeks | High | When the team can't pause |\n\n## Common mistakes to avoid\n\n**Casting to `any` to make errors disappear.** You've thrown away the safety this migration is trying to gain. If you must escape, use `unknown` and explicit narrowing.\n\n**Skipping `strictNullChecks`.** It's the painful flag, but it's also the one that catches real bugs. Don't half-migrate.\n\n**Not pinning the TS version.** Strict-mode behavior subtly changes across TS minors. Pin during migration.\n\n**Trying to perfect types instead of preserving behavior.** First pass is \"make it compile\". Second pass is \"tighten types properly\".\n\n**Suppressing whole files with `// @ts-nocheck`.** It works as triage, but tracks tech debt; build a backlog of files to revisit.\n\n## FAQ\n\n**Should I enable `noUncheckedIndexedAccess`?**\nYes, eventually. It's not part of `strict` but catches a lot of array/object access bugs. Save it for after the strict flags.\n\n**What about `exactOptionalPropertyTypes`?**\nStrict in spirit but not in `strict: true`. Mixed reception in the community; consider for new projects, skip for migrations.\n\n**Is `unknown` always better than `any`?**\nYes. `unknown` requires narrowing at the use site; `any` skips type-checking entirely. The narrowing forces explicit handling.\n\n**Will strict mode slow my builds?**\nMinor — single-digit % typically. Not a real concern.\n\n## Where to go next\n\nFor related guides see [Next.js 15 Server Actions guide for 2026](/blog/nextjs-15-server-actions-guide-2026), [Vitest vs Jest in 2026](/blog/vitest-vs-jest-2026), and [Drizzle vs Prisma in 2026](/blog/drizzle-vs-prisma-2026).","hue":150,"metaTitle":"TypeScript Strict Mode Migration Guide (2026)","metaDescription":"Step-by-step guide to migrating a legacy TypeScript codebase to strict mode in 2026 — flag order, AI codemods, common error fixes, CI gating.","keywords":["typescript strict mode","ts strict migration","strictnullchecks migration","noimplicitany","typescript codemod","ts-morph migration","typescript 5.5","typescript best practices 2026","typescript ai codemod","tsconfig strict"],"tldr":["**Don't enable `strict: true` all at once.** Enable individual flags in this safe order: noImplicitAny → strictNullChecks → strictFunctionTypes → noImplicitReturns → strictBindCallApply.","**`strictNullChecks` is the painful one** — usually 70% of the work.","**AI-assisted codemods now handle 80% of the migration.** Plumbing through Claude or ts-morph beats hand-edits.","**Block PRs from regressing.** Add `--noEmitOnError` in CI from day one."],"readTime":"3 min read","wordCount":690},"related":[{"slug":"how-to-learn-typescript-2026","title":"How to learn TypeScript in 2026: from JavaScript to typed confidence","excerpt":"TypeScript is now the default language for serious JavaScript projects. Here is the practical 2026 path to learning it without getting lost in complexity.","category":"code","date":"April 1, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":313},{"slug":"how-to-learn-typescript-fast-2026","title":"How to learn TypeScript fast in 2026 (a 2-week plan for JS devs)","excerpt":"A focused two-week plan to take a working JavaScript developer to confident TypeScript. Real exercises, real config, no busywork.","category":"code","date":"January 23, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":305},{"slug":"how-to-use-typescript-with-react-2026","title":"How to Use TypeScript With React in 2026 Without the Pain","excerpt":"A practical 2026 walkthrough for wiring TypeScript into React: project setup, typing props and hooks, handling events, and the patterns worth skipping.","category":"code","date":"May 3, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":168}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"prompt-injection-attacks-2026","title":"Prompt injection attacks in 2026: real exploits seen and how to defend","excerpt":"Prompt injection moved from theoretical to common in 2025-2026. Here are the real attacks teams have seen, the defensive patterns that work, and the OWASP LLM Top 10 for 2026.","category":"ai","date":"February 4, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":192},"older":{"slug":"ups-sizing-guide-2026","title":"UPS Sizing: Enough Runtime to Shut Down Safely","excerpt":"A battery backup is not there to keep you working through an outage. It is there to bridge brief interruptions and to shut things down cleanly, which needs far less capacity than people buy.","category":"tech","date":"February 4, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":232}}