Turn on noUncheckedIndexedAccess so indexing an array or a string-keyed record types as T | undefined, which is what it is at runtime.
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true
}
}
const users: User[] = [];
const first = users[0]; // User | undefined
const byId: Record<string, User> = {};
const u = byId["missing"]; // User | undefined
Without the flag both are typed User, and users[0].name compiles then throws Cannot read properties of undefined on an empty array.
What changes in existing code
Every index read needs a check or a non-null assertion. The honest patterns:
const first = users[0];
if (!first) return;
first.name;
const last = users.at(-1) ?? fallback;
for (const user of users) user.name; // iteration was always safe
Loops indexed by i are the noisy case. for...of, .map, and .entries() don’t index, so they need no change.
Gotchas
- Tuples and known keys are unaffected.
const [a, b] = pairandobj.knownKeystay precise; only computed and numeric index reads widen. strictdoesn’t include this flag. It has to be set on its own.- Turning it on late in a project produces hundreds of errors in one go. Enable it, fix the real ones, and reach for
!only where the index is provably in range, such as right after a length check the compiler can’t follow. - Writes are unaffected.
arr[i] = xstill typesxasT, notT | undefined.