The hidden bug
With "strict": false, tsc checks app.ts and reports zero errors. But look closer: find gives undefined when no name matches, and s on line 3 has no type, so nothing about s is checked.
No name is "Bo", so who is undefined. It flows into shout, and s.toUpperCase() runs on undefined. Node.js stops with a TypeError. The checker said nothing, because those checks were off.
One switch
Strict mode is one setting in tsconfig.json: "strict": true. It does not add new syntax. It tells tsc to check harder, so more mistakes are caught before the program ever runs.
In TypeScript 5.9, strict turns on a family of 9 checks. Two catch our bugs: noImplicitAny, every value needs a known type, and strictNullChecks, null and undefined must be handled.
What it catches
tsc now stops at line 3: Parameter 's' implicitly has an 'any' type. any means anything goes, so nothing about s was checked. Strict mode makes you say what s is.
We write s: string and check again. Now line 6 fails: who has type string | undefined, meaning a string or undefined. shout only takes a string. This is the crash, found before running.
who ?? "nobody" means: use who, but if it is null or undefined, use "nobody". The result is always a string, so tsc checks again and reports zero errors.
tsc writes app.js and Node.js runs it. who is still undefined, but the code now handles that, so shout gets "nobody" and prints NOBODY. No crash.
In practice
tsc --init writes "strict": true for new projects. For older code, you can turn strict on and switch single checks off, such as "strictNullChecks": false, then fix files one at a time.
What happens
;; step 1/9 · loose
tsconfig.json: "strict": false
$ tsc -p .
(no errors)
1 const names = ["Ada", "Lin"];
> 2 const who = names.find(n => n === "Bo");
> 3 function shout(s) {
4 return s.toUpperCase();
5 }
6 console.log(shout(who));
The list of nine is TypeScript 5.9's. New TypeScript versions sometimes add a check to the strict family, so upgrading can show new errors in strict projects. Strict mode only changes the checking, with one small exception: alwaysStrict makes tsc put "use strict"; at the top of each JavaScript file it writes.