TypeScript's value is proportional to how honestly it is used. A large codebase with permissive types carries the syntax cost of static typing while collecting almost none of the benefit.
Turn strict on, and keep it on
Strict mode is the difference between TypeScript catching real defects and TypeScript decorating your JavaScript. Null and undefined handling in particular is where most runtime errors originate, and non-strict mode ignores exactly that class.
On an existing codebase, enable strict flags one at a time and fix as you go. It is slower than a single flip, and it is the version that actually gets finished.
Ban `any` and reach for `unknown`
`any` disables checking for everything it touches, and it spreads: an `any` returned from a function contaminates every caller silently.
`unknown` is the honest alternative for genuinely unknown data. It forces a narrowing check before use, which is precisely the check you wanted anyway at an API boundary.
- Enable strict, noUncheckedIndexedAccess and noImplicitOverride.
- Lint `any` as an error, with a required justification comment for exceptions.
- Validate external data at the boundary and type the parsed result.
- Prefer discriminated unions to optional-field soup.
Model states as unions, not optional flags
An object with `isLoading`, `data` and `error` all optional permits many combinations that cannot actually occur, and every consumer must defensively handle them.
A discriminated union on a status field makes the impossible states unrepresentable. The compiler then guarantees exhaustive handling, and the defensive branches disappear because they are provably unreachable.
Types are not validation
This is the mistake that produces the most production incidents. Types vanish at runtime; an API response typed as a shape is an assertion, not a check.
Validate at every trust boundary — network responses, form input, environment variables, message payloads — with a runtime schema, and derive the static type from that schema so the two cannot drift.
Key takeaways
- Strict mode is where the actual defect-catching happens.
- Use `unknown` instead of `any`; it forces the check you needed.
- Discriminated unions make impossible states unrepresentable.
- Types are erased at runtime — validate every trust boundary.
Ready to make the switch?
Try Zero Delay Analytics free. No credit card required, and no cookie banner needed.
Get Started