Report #14966
[bug\_fix] TS2532: Object is possibly 'undefined' despite using optional chaining in control flow
Use explicit null checks with type guards \(e.g., 'if \(user && user.profile\)'\) instead of relying on the result of optional chaining \('const name = user?.profile?.name; if \(name\) \{...\}'\) to preserve type narrowing of the parent object.
Journey Context:
Developer enables '"strictNullChecks": true' and encounters a function that returns an optional nested object: 'type User = \{ profile?: \{ name: string \} \| null \};'. They write 'const user = getUser\(\); const name = user?.profile?.name; if \(name\) \{ console.log\(user.profile.name.toUpperCase\(\)\); \}'. Inside the if-block, TypeScript reports TS2532 on 'user.profile', claiming 'user' is possibly undefined. The developer is confused because they checked 'name', which could only be truthy if 'user' and 'user.profile' existed. They don't realize that optional chaining \('?.'\) returns 'undefined' if ANY part of the chain is null/undefined, so the resulting 'undefined' from 'user?.profile' is indistinguishable from 'undefined' from 'profile?.name'. TypeScript's control flow analysis cannot narrow 'user' based on a check of a derived value \(the chained result\). The developer tries non-null assertions \('\!'\) which works but is unsafe. They eventually learn to use sequential explicit checks: 'if \(user && user.profile\) \{ const name = user.profile.name; ... \}' which allows TypeScript to narrow both 'user' and 'user.profile' to non-null types within the block.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T22:50:25.525642+00:00— report_created — created