Solve - Object is possibly null (document.getElementById)

avatar

Borislav Hadzhiev

Last updated: Mar 31, 2022

banner

Photo from Unsplash

Solve - Object is possibly null (document.getElementById) #

The error "Object is possibly null" with document.getElementById occurs because the method returns null if no element with the provided id is found. To solve the error use a non-null assertion or a type guard to verify the variable does not store a null value.

object possibly null

This is the index.html file for the examples in this article.

index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> </head> <body> <button id="btn">Click</button> <script src="./src/index.ts"></script> </body> </html>

And here are 2 examples of how the error occurs.

index.ts
// 👇️ const button: HTMLElement | null const button = document.getElementById('btn'); // ⛔️ Object is possibly 'null'.ts(2531) button.addEventListener('click', () => { console.log('button clicked'); }); // ⛔️ Object is possibly 'null'.ts(2531) console.log(button.innerText);

The document.getElementById method returns null if no element with the provided id is found in the DOM.

The button variable has a type of HTMLElement | null, therefore we can't directly access a property on it, because if we access a property on a null value, we'd get a runtime error.

The best way to solve the error is to use a simple if statement that serves as a type guard.

src/index.ts
// 👇️ const button: HTMLElement | null const button = document.getElementById('btn'); // 👉️ button has type HTMLElement or null here if (button != null) { // 👉️ button has type HTMLElement here button.addEventListener('click', () => { console.log('button clicked'); }); console.log(button.innerText); }

We make sure that the button variable does not store a null value before accessing properties on it.

Once we enter the if block, TypeScript knows that the type of the button variable is HTMLElement and it couldn't be null.

An alternative approach to solve the error is to use the optional chaining (?.) operator.

src/index.ts
// 👇️ const button: HTMLElement | null const button = document.getElementById('btn'); // 👇️ using optional (?.) chaining button?.addEventListener('click', () => { console.log('button clicked'); }); // 👇️ using optional chaining (?.) console.log(button?.innerText);

The optional chaining (?.) operator short-circuits returning undefined if the reference is nullish (null or undefined).

In other words, if the button variable stores a null value, we won't attempt to access the addEventListener method and get a runtime error.

We could have also used the non-null assertion (!) operator.

src/index.ts
// 👇️ const button: HTMLElement | null const button = document.getElementById('btn'); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion button!.addEventListener('click', () => { // 👈️ non-null assertion console.log('button clicked'); }); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion console.log(button!.innerText); // 👈️ non-null assertion

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.

This is very similar to a type assertion and should only be used when you're absolutely sure that the value is of the expected type.

src/index.ts
const button = document.getElementById('btn') as HTMLElement; button.addEventListener('click', () => { console.log('button clicked'); }); console.log(button.innerText);

Type assertions are used when we have information about the type of a value that TypeScript can't know about.

We effectively tell TypeScript that button will be an HTMLElement and not to worry about it.

We could have also used a more specific type - HTMLButtonElement, because we're working with a button element.

src/index.ts
const button = document.getElementById('btn') as HTMLButtonElement; button.addEventListener('click', () => { console.log('button clicked'); }); console.log(button.innerText);

Using a more specific type enables us to access button-specific properties that don't exist in the HTMLElement interface.

The types are consistently named as HTML***Element. Once you start typing HTML.., your IDE should be able to help you with autocomplete.

Some commonly used types are: HTMLInputElement, HTMLButtonElement, HTMLAnchorElement, HTMLImageElement , HTMLTextAreaElement, etc.

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.