How it works
The explanation, with examples you can run.
What is in the family
In TypeScript 5.x, strict enables:
| Flag | What it catches |
|---|---|
strictNullChecks | Using a value that may be null or undefined without checking |
noImplicitAny | Parameters and variables the checker would have to give any |
strictFunctionTypes | Callbacks that expect a narrower argument than they will be given |
strictBindCallApply | Wrong arguments to fn.call, fn.apply and fn.bind |
strictPropertyInitialization | Class fields that the constructor never sets |
noImplicitThis | this with an unknown type inside functions |
useUnknownInCatchVariables | Treating a caught value as an Error without checking |
strictBuiltinIteratorReturn | Treating next().value of a finished built-in iterator as a real value (it is undefined, not any) |
alwaysStrict | Emits "use strict" and parses every file in strict mode |
Each can still be turned off individually ("strictPropertyInitialization": false), which is useful while migrating.
The one that matters most
type User = { id: string; name: string }declare const users: User[] const u = users.find((x) => x.id === "u1")console.log(u.name) // Error: 'u' is possibly 'undefined' if (u) console.log(u.name) // fine: narrowed to Userconsole.log(u?.name ?? "unknown") // fine: handles the missing caseWithout strictNullChecks, the type of u is plain User, and the first console.log compiles and then throws TypeError: Cannot read properties of undefined the first time no user matches. Missing values are the most common runtime error in JavaScript, and this flag is what lets the checker see them.
noImplicitAny
function total(items) { // Error: Parameter 'items' implicitly has an 'any' type let sum = 0 for (const item of items) sum += item.price return sum}Without the flag, items is silently any and nothing in the function is checked. With it, you have to say what items is, or write any explicitly, where reviewers can see it.
Beyond strict
const scores: Record<string, number> = { ada: 3 }const s = scores["lin"] // number, under strict aloneThe lookup returns undefined at runtime, but its type says number. noUncheckedIndexedAccess makes it number | undefined, at the cost of extra checks on array access in loops. exactOptionalPropertyTypes stops { name?: string } from accepting an explicit name: undefined. Neither is in strict; both are worth trying on new code.
Turning it on in an existing project
Switching on strict in a large JavaScript-flavoured codebase can produce thousands of errors. Enable the flags one at a time, starting with noImplicitAny and then strictNullChecks, and fix each kind of error before the next. Tools that track and suppress existing errors per file let new code meet the strict rules while old code catches up.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.