TS2532: Object is possibly 'undefined'

Quick answer

Under strictNullChecks the value's type includes undefined, so accessing it could crash. Prove it's defined first: optional chaining value?.prop, a guard (if (value)), or a default (value ?? fallback). Use value! only when you're certain. It's the compile-time version of the runtime Cannot read properties of undefined.

The exact error string

function len(s?: string) {
  return s.length;
}
// error TS2532: Object is possibly 'undefined'.

const el = document.getElementById("app");
el.innerHTML = "";
// error TS2532: Object is possibly 'null'. (getElementById returns T | null)

How to diagnose it (where does undefined come from?)

TS2532 always points at a value whose type is T | undefined. Hover it and find why undefined is in the type — the source decides the cleanest fix:

Fix 1: optional chaining (quickest)

return s?.length;             // undefined instead of throwing
return s?.length ?? 0;        // with a fallback value

Fix 2: a guard (narrows the type)

function len(s?: string) {
  if (s === undefined) return 0;   // early return
  return s.length;                 // ✅ s is string here
}

if (el) el.innerHTML = "";         // narrowed inside the block

Fix 3: a default with ??

const value = s ?? "";           // never undefined from here
return value.length;

Fix 4: non-null assertion (only when certain)

const el = document.getElementById("app")!;   // you know #app exists
el.innerHTML = "";

Worked example: optional fields in API JSON

APIs omit optional fields, so a generated/accurate interface marks them ? — and then every access is correctly flagged by TS2532. That's the type system doing its job:

interface User { name: string; address?: { city: string } }  // address is optional

const user: User = await (await fetch("/api/user")).json();
user.address.city;               // error TS2532: Object is possibly 'undefined'
user.address?.city ?? "—";       // ✅ handle the missing case

Generate the interface from a real payload with JSON to TypeScript and mark genuinely-optional fields ? — TS2532 then forces you to handle exactly the cases the API can actually produce.

TS2532 in React

// 1) useContext with an undefined default
const Ctx = createContext<Theme | undefined>(undefined);
const theme = useContext(Ctx);
theme.color;                      // ❌ TS2532
// custom hook that throws if missing -> returns a defined Theme:
function useTheme() {
  const t = useContext(Ctx);
  if (!t) throw new Error("useTheme must be used within ThemeProvider");
  return t;                       // ✅ Theme, not Theme | undefined
}

// 2) router params / a find() result
const item = items.find(i => i.id === id);
item?.name;                       // ✅ find() can return undefined

Common variants of this message

VariantTypical causeFix
Object is possibly 'undefined'optional value / find()optional chaining or guard
Object is possibly 'null'getElementById etc.guard or ! when certain
Object is possibly 'null' or 'undefined' (TS2533)value is T | null | undefinednarrow both
'x' is possibly 'undefined' (TS18048)newer wording, named valuesame — narrow/guard
appears on arr[i]noUncheckedIndexedAccessguard the indexed result

Debugging checklist

Frequently Asked Questions

How is TS2532 different from TS18048 and TS2533?

They are the same null-safety family. TS2532 is 'Object is possibly undefined' (an expression result); TS18048 is "'x' is possibly 'undefined'" (newer wording naming a specific value); TS2533 is 'Object is possibly null or undefined'. All are fixed by narrowing or guarding before access.

Why does TS2532 appear on arr[i] after I enabled a flag?

noUncheckedIndexedAccess types every indexed access arr[i] and obj[key] as T | undefined, because the index might be out of range or the key absent. That is intentional safety — guard the result, use optional chaining, or check length/existence before using it.

Does a guard like if (a && a.b) still narrow in TS2532?

Yes for locals, but a narrowing can be "lost" if a function call happens in between, or if the value is a mutable object property TypeScript can't prove is unchanged. Copy it to a const first (const x = obj.maybe; if (x) x.use()), which narrows reliably.

Why is useContext possibly undefined in React?

If you call createContext<Ctx | undefined>(undefined), the hook returns Ctx | undefined, so every use hits TS2532. Either provide a non-undefined default, or write a custom useX hook that throws if the context is missing and returns the narrowed, defined value.

Is the non-null assertion (!) safe to use?

Only when you are certain the value is defined and the compiler cannot see it. value! removes the check but does nothing at runtime, so a wrong assertion throws 'cannot read properties of undefined'. Prefer a real guard whenever the value could genuinely be missing.

Will disabling strictNullChecks make TS2532 go away?

Yes, but don't. strictNullChecks is what turns runtime 'cannot read properties of undefined' crashes into compile-time errors. Turning it off removes the safety across the whole project. Fix the single undefined case the error points at instead.

Typing an API response?

Generate an interface from a real payload (with optional fields marked) using JSON to TypeScript — nothing is uploaded to a server.

JSON to TypeScript JSON Formatter All Error References
About the author

Pasindu Ishan is a software developer based in Sri Lanka. He builds privacy-first developer tools at JSON Dev Tools.