Last updated: Feb 27, 2024
Reading timeยท5 min
The "Object is possibly 'undefined'" error occurs when we try to access a
property on an object that may be undefined
(e.g. marked as optional).
To solve the error, use optional chaining to short-circuit if the reference is
equal to null
, e.g. p1?.address?.country
.
Here is an example of how the error occurs.
type Person = { address?: { // ๐๏ธ could be undefined country?: string; city?: string; }; }; const p1: Person = {}; // โ๏ธ Error: Object is possibly 'undefined'.ts(2532) p1.address.country;
The address
property on the Person
type is marked as
optional,
so it might be undefined
.
This is why we aren't able to safely access the country
or city
properties.
You can use the optional chaining (?.) operator to resolve the issue.
type Person = { address?: { country?: string; city?: string; }; }; const p1: Person = {}; // โ No error const result = p1?.address?.country; console.log(result); // ๐๏ธ undefined
The question mark dot (?.) syntax is called optional chaining in TypeScript.
It is like using dot notation to access a nested property of an object but
instead of throwing an error if the reference is nullish (null
or
undefined
), it short-circuits returning undefined
.
You can combine the optional chaining (?.) operator with the nullish coalescing (??) operator to specify a default value if the property doesn't exist.
type Person = { address?: { // ๐๏ธ could be undefined country?: string; city?: string; }; }; const p1: Person = {}; const result = p1?.address?.country ?? 'fallback value'; console.log(result); // ๐๏ธ fallback value
If the value to the left of the
nullish coalescing operator (??)
is equal to null
or undefined
, the value to the right is returned,
otherwise, the value to the left of the operator is returned.
If trying to access the nested country
property on the object returns
undefined
, then the value to the right of the nullish coalescing (??) operator
is returned.
if
statement to solve the errorAn alternative approach is to use a simple if
statement as a
type guard.
type Person = { address?: { country?: string; city?: string; }; }; const p1: Person = {}; if (p1.address != undefined) { console.log(p1.address.country?.toUpperCase); console.log(p1.address.city?.toUpperCase); }
We used an if
statement to check if the p1.address
property is not equal to
undefined
or null
.
if
block, TypeScript knows that the p1.address
property is of type object, and not undefined
.Notice that we used the loose inequality (!=) operator, which checks for both
undefined
and null
. You can exclusively check for undefined
with strict
not equals (!==).
The loose comparison covers both undefined
and null
, because in a loose
comparison undefined
is equal to null
.
console.log(undefined == null); // ๐๏ธ true console.log(undefined === null); // ๐๏ธ false
If you are sure the property cannot possibly have a null value, you can use the non-null assertion operator.
type Person = { address?: { country?: string; city?: string; }; }; const p1: Person = { address: { country: 'Chile', city: 'Santiago', }, }; console.log(p1.address!.country); // ๐๏ธ "Chile" console.log(p1.address!.city); // ๐๏ธ "Santiago"
The exclamation mark is the non-null assertion operator in TypeScript.
null
and undefined
from a type without doing any explicit type-checking.When you use this approach, you basically tell TypeScript that this value will
never be null
or undefined
.
We used it right after the address
property, so we are telling TypeScript that
p1.address
will never have a value of null
or undefined
.
If you are making a comparison in an if
statement, use the logical AND (&&)
operator to make sure the property is of the correct type.
type Person = { address?: { country?: string; city?: string; num?: number; }; }; const p1: Person = {}; if ( p1?.address && typeof p1.address.num === 'number' && p1.address.num > 10 ) { console.log('success'); }
The logical AND (&&) operator makes sure the address
property isn't
undefined
, that num
exists on the object and is a number
before comparing
it to the number 10
.
This is needed because if the reference is nullish (null
or undefined
), the
optional chaining operator (?.) will return undefined
and TypeScript doesn't
allow us to compare undefined
to a number
.
For example, this would fail:
type Person = { address?: { country?: string; city?: string; num?: number; }; }; const p1: Person = {}; // โ๏ธ Error: Object is possibly 'undefined'.ts(2532) if (p1?.address?.num > 10) { console.log('success'); }
The result might have a value of undefined
because that's the return value of
the optional chaining (?.) operator when it short-circuits.
The num
property might have a value of undefined
, so we can't directly
compare it to a number
.
Another common way to avoid getting the error is to use the logical AND (&&) operator.
type Person = { address?: { country?: string; city?: string; }; }; const p1: Person = {}; if (p1.address && p1.address.country) { // ๐๏ธ const result: string const result = p1.address.country; }
undefined
).All the values in the if
condition have to be truthy for the if
block to
run.
The falsy values in JavaScript are: undefined
, null
, false
, 0
, ""
(empty string), NaN
(not a number).
All other values are truthy.
This is why TypeScript is able to infer the type of the result
variable to be
string
in the if
block.
typeof
operator to solve the errorAn even better way to get around the error in this situation is to use the typeof operator.
type Person = { address?: { country?: string; city?: string; }; }; const p1: Person = {}; if (p1.address && typeof p1.address.country === 'string') { // ๐๏ธ const result: string const result = p1.address.country; }
We explicitly check if the type of the country
property is a string.
This is better than checking if the value is truthy
because empty strings are
falsy values in JavaScript (and TypeScript).
Here is an example that illustrates why using the typeof
operator is better.
type Person = { address?: { country?: string; city?: string; }; }; const p1: Person = { address: { country: '' } }; if (p1.address && p1.address.country) { // โ๏ธ This doesn't run const result = p1.address.country; console.log(result); } else { // ๐๏ธ this block runs console.log('โ this runs'); }
This else
block runs in the example above.
country
property points to an empty string (falsy value), so just checking if the value is truthy might not be enough in your scenario.It's always better to be explicit and use the typeof
operator when possible.
It helps us avoid some difficult-to-spot bugs.
The "Object is possibly 'undefined'" error occurs when we try to access a
property on an object that may have a value of undefined
.
To solve the error, use the optional chaining operator or a type guard to make
sure the reference is not undefined
before accessing properties.
You can learn more about the related topics by checking out the following tutorials: