JavaScript / Editorial solution guide
TypeError while reading undefined or null
Trace the missing value to its boundary instead of hiding every failure with optional chaining. Diagnose search results, DOM selectors, incomplete returns, and invalid response shapes using synthetic records.
Read-only knowledge base ยท No public comments
Recognize the symptoms
A property read fails only when no course matches, before markup is ready, or after a request returns an unexpected shape. Engines phrase TypeError messages differently; preserve the exact observed message and stack locally, then identify the base value immediately before the failed access.
Understand the likely causes
- find can return undefined and querySelector can return null. A missing return can produce undefined, an API may intentionally use null, and typeof null is historically "object". Reading a nested field without checking these boundary outcomes causes failure. A blanket fallback can conceal a required record that should be rejected.
1. Locate the first invalid assumption
Break a long expression into named steps: the response, decoded record, matching course, and title. Inspect type and presence using synthetic data, not a full private response dump. Check whether the failure precedes data arrival, follows a no-match search, or occurs after a function returns without a value. Start from the first invalid boundary rather than adding checks to every downstream property. A selector failure needs markup/lifecycle investigation; a missing search result needs a domain no-match policy.
2. Decide whether absence is allowed
An optional subtitle can legitimately be absent, while an enrollment action may require a valid course. Use optional chaining for the former and an explicit rejection for the latter. Nullish coalescing preserves meaningful zero and empty-string values, unlike OR, but neither operator validates a record. Require data !== null before treating an object-like value as a record, then validate its allowed fields. Do not interpret every undefined as an empty list; that can convert an integration defect into a misleading successful screen.
3. Repair the boundary contract
The local lookup below returns a tagged result for an expected no-match case. Callers branch on ok before reading title, so absence cannot masquerade as a valid record. For a required DOM node, check the selector and run setup after markup exists; if it is a configuration error, fail clearly instead of quietly disabling the feature. If an async function omitted return, repair its output contract rather than defaulting every caller to an empty object.
function lookup(courses, id) {
const course = courses.find(item => item.id === id);
return course === undefined
? { ok: false, error: "course missing" }
: { ok: true, title: course.title };
}
const courses = [{ id: 1, title: "DOM" }];
console.log(JSON.stringify(lookup(courses, 1)));
console.log(JSON.stringify(lookup(courses, 2)));
{"ok":true,"title":"DOM"}
{"ok":false,"error":"course missing"}
Both branches are observable without deliberately crashing the program or relying on engine-specific error wording.
4. Keep unexpected failures visible
Do not surround the whole feature with catch returning undefined, because that erases the distinction between missing data and programmer defects. Handle expected absence where its meaning is known, preserve useful cause context, and present a safe message at the UI boundary. Check interrupted optional chains too: grouping an optional access and then reading another property can resume an unsafe ordinary access. Optional chaining short-circuits a particular chain; it is not a general exception suppressor or a substitute for understanding the data contract.
Verify the fix
Verify matching, no-match, empty-list, explicit-null, and malformed-record cases under the intended contract. For DOM setup, test both normal markup and a missing required node. Confirm the fix preserves valid zero/empty optional fields and that required actions do not proceed on invalid records. Retain the smallest reproducer and the observed boundary value.
Keep it from recurring
- Name boundary results, validate external shapes once, and test every documented absence path. Keep expected optional data separate from required domain state. Review return paths and selector lifecycle before adding fallback objects that make broken assumptions harder to notice.