"strict": true on a codebase that has been running happily without it
produces a number. The number is large. The number is also misleading, because
the errors are not evenly distributed — they cluster into about four shapes,
and once you have fixed one of each, the rest is mechanical.
Shape one: things that were always null
strictNullChecks finds the places where a value is optional in the type and
mandatory in the code. Most of these are real. A handful are cases where the
type is simply wrong — the API always sends the field — and the honest fix is
to correct the type, not to append ! and move on.
Shape two: implicit any at the boundaries
Every untyped callback parameter, every catch (e), every third-party module
without types. These are noise, and they are fastest to clear in one pass with
a rule: nothing gets any, everything gets unknown plus a narrowing check.
Shape three: the class fields
strictPropertyInitialization complains about anything assigned outside the
constructor. Dependency-injected fields, test fixtures, framework-populated
properties. This is the one where ! is often correct — the framework really
does guarantee it — but each one deserves a comment saying which framework and
why.
Shape four: actual bugs
The reason to do this. In my case: two off-by-one array accesses that could
return undefined, one function that returned void down a branch nobody had
hit yet, and a date-parsing path that produced Invalid Date and then
cheerfully formatted it.
Four real bugs is not a landslide. But they were shipped, and none of them had a test, and the compiler found them for free.
Doing it again
Incrementally, from the start, per-directory if the tooling allows. The all-at-once version works, but it produces a single enormous diff that no reviewer can meaningfully read — which is its own kind of risk.