Object is possibly 'null' or 'undefined' error in TS

avatar

Borislav Hadzhiev

Last updated: Mar 24, 2022

banner

Photo from Unsplash

Object is possibly 'null' or 'undefined' error in TS #

The "Object is possibly 'null' or 'undefined'" error occurs when we try to access a property on an object that may have a value of null or undefined. To solve the error, use optional chaining to short-circuit if the reference is nullish, e.g. person?.address?.country.

object is possibly null or undefined

Here is an example of how the error occurs.

index.ts
type Person = { address?: { // 👈️ may be null or undefined country?: string; city?: string; } | null; }; const person: Person = {}; // ⛔️ Error: Object is possibly 'null' or 'undefined'. console.log(person.address.country);

The address property on the Person type is marked as optional and can also be null.

This is why we aren't able to safely access the country or city properties on the object.

To get around this, we can use the optional chaining (?.) operator.

index.ts
type Person = { address?: { country?: string; city?: string; } | null; }; const person: Person = {}; // 👇️ const result: string | undefined const result = person?.address?.city;

The question mark dot (?.) syntax is called optional chaining in TypeScript and is like using dot notation to access a nested property of an object, but instead of causing an error if the reference is nullish (null or undefined), it short-circuits returning undefined.

This approach is commonly used when fetching data from a remote API or reading it from a file, where some of the properties might not have a value.

An alternative approach is to use a simple if statement as a type guard.

index.ts
type Person = { address?: { country?: string; city?: string; } | null; }; const person: Person = {}; // 👇️ checks for both null and undefined if (person.address != null) { console.log(person.address.country); console.log(person.address.city); }

We used an if statement to check if the person.address property is not equal to null or undefined.

Once we enter the if block, TypeScript knows that the address property is an object, and not null or undefined.

Notice that we used loose not equals (!=), which checks for both null and undefined.

The loose comparison covers both null and undefined, because in a loose comparison null is equal to undefined.

index.ts
console.log(null == undefined); // 👉️ true console.log(null === undefined); // 👉️ false

If you are sure the property could not have a value of null or undefined, you can use the non-null assertion operator.

index.ts
type Person = { address?: { country?: string; city?: string; } | null; }; const person: Person = { address: { country: 'Austria', city: 'Linz', }, }; // 👇️ non-null assertion operator console.log(person.address!.city); // 👉️ "Austria" console.log(person.address!.country); // 👉️ "Linz"

The exclamation mark is the non-null assertion operator in TypeScript.

It removes 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 person.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.

index.ts
type Person = { address?: { country?: string; city?: string; streetNumber?: number; } | null; }; const person: Person = {}; if ( person?.address && typeof person.address.streetNumber === 'number' && person.address.streetNumber > 5 ) { console.log('success'); }

The logical AND (&&) operator makes sure the address property is not null or undefined and that the streetNumber property exists on the object and is a number before comparing it to the number 5.

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:

index.ts
type Person = { address?: { country?: string; city?: string; streetNumber?: number; } | null; }; const person: Person = {}; // ⛔️ cannot compare possibly undefined to number if (person?.address?.streetNumber > 5) { 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 streetNumber property might have a value of undefined, so we can't directly compare it to a number.

Another common way to avoid getting the "Object is possibly null or undefined" error is to use the logical AND (&&) operator.

index.ts
type Person = { address?: { country?: string; city?: string; } | null; }; const person: Person = {}; if (person.address && person.address.city) { // 👇️ const result: string const result = person.address.city; }
The logical AND (&&) operator won't evaluate the value to the right if the value to the left is falsy (e.g undefined).

If person.address returns undefined, then person.address.city won't get evaluated at all, so we won't get an error.

All of the values in the if condition have to be truthy for the if block to run.

The truthy values are all values that are not falsy.

The falsy values in JavaScript are: null, undefined, false, 0, "" (empty string), NaN (not a number).

This is why TypeScript is able to infer the type of the result variable to be string in the if block.

An even better way to get around the "Object is possibly null or undefined" error in this situation is to use the typeof operator.

index.ts
type Person = { address?: { country?: string; city?: string; } | null; }; const person: Person = {}; if (person.address && typeof person.address.city === 'string') { // 👇️ const result: string const result = person.address.city; }

We explicitly check if the type of the city 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 typeof is better.

index.ts
type Person = { address?: { country?: string; city?: string; } | null; }; const person: Person = { address: { city: '' } }; if (person.address && person.address.city) { // 👉️ does NOT run console.log('⛔️ this does NOT run'); } else { // 👉️ else block runs console.log('✅ this runs'); }

The else block runs in the example above.

The city 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, because it helps us avoid some difficult to spot bugs.

Conclusion #

The "Object is possibly null or undefined" error occurs when we try to access a property on an object that may be null or undefined. To solve the error, use the optional chaining operator or a type guard to make sure the reference is not nullish before accessing properties.

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.