Type 'HTMLElement or null' is not assignable to type in TS

avatar
Borislav Hadzhiev

Last updated: Jan 15, 2023
7 min

banner

# Table of Contents

  1. Type 'HTMLElement or null' is not assignable to type in TS
  2. Argument of type 'HTMLElement' not assignable to type in TS
  3. (React) Argument type 'HTMLElement or null' not assignable to parameter type 'Element or DocumentFragment'

# Type 'HTMLElement or null' is not assignable to type in TS

The "Type 'HTMLElement | null' is not assignable to type" error occurs when a possibly null value is assigned to something that expects an element.

To solve the error, use a non-null assertion or a type guard to verify the value is an element before the assignment.

htmlelement or null not assignable type

This is the HTML code for the examples.

index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> </head> <body> <input id="submit" type="submit" name="submit" /> <script src="./src/index.ts"></script> </body> </html>

And here are 3 examples of how the error occurs.

src/index.ts
// ๐Ÿ‘‡๏ธ const input: HTMLElement | null const input = document.getElementById('submit'); // โ›”๏ธ Type 'HTMLElement | null' is not assignable to type 'HTMLElement'. // Type 'null' is not assignable to type 'HTMLElement'.ts(2322) const el1: HTMLElement = input; // --------------------------------------- // โ›”๏ธ Type 'HTMLElement | null' is not assignable to type 'Element'. // Type 'null' is not assignable to type 'Element'.ts(2322) const el2: Element = input; // --------------------------------------- function example(el: Element) { return el; } // โ›”๏ธ Argument of type 'HTMLElement | null' is not assignable // to parameter of type 'Element'. // Type 'null' is not assignable to type 'Element'.ts(2345) example(input);
The code for this article is available on GitHub

The input variable has a type of HTMLElement | null.

The el1 and el2 variables have a type of HTMLElement and Element, so they only expect to get assigned a value of that type.

TypeScript is basically telling us that the input variable might have a value of null which is not compatible with the type of the el1 variable which only expects an HTMLElement.

# Using the non-null assertion operator

Here are a couple of examples of how you can solve the error.

src/index.ts
// ๐Ÿ‘‡๏ธ const input: HTMLElement | null const input = document.getElementById('submit'); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const el1: HTMLElement = input!; // ๐Ÿ‘ˆ๏ธ non-null assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const el2: Element = input!; // ๐Ÿ‘ˆ๏ธ non-null assertion function example(el: Element) { return el; } // eslint-disable-next-line @typescript-eslint/no-non-null-assertion example(input!); // ๐Ÿ‘ˆ๏ธ non-null assertion

using non null assertion operator to solve the error

The code for this article is available on GitHub

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.

# Using a type assertion

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 input = document.getElementById('submit'); const el1: HTMLElement = input as HTMLElement; // ๐Ÿ‘ˆ๏ธ type assertion const el2: Element = input as Element; // ๐Ÿ‘ˆ๏ธ type assertion function example(el: Element) { return el; } example(input as HTMLElement); // ๐Ÿ‘ˆ๏ธ type assertion

using type assertion to solve the error

The code for this article is available on GitHub

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 el1 will be an HTMLElement and not to worry about it.

You can also use a type assertion directly when selecting the element.

src/index.ts
// ๐Ÿ‘‡๏ธ used type assertion here const input = document.getElementById('submit') as HTMLInputElement; const el1: HTMLElement = input; const el2: Element = input; function example(el: Element) { return el; } example(input);

We typed the input element as HTMLInputElement effectively removing null from its type.

The types are consistently named 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, HTMLDivElement, HTMLTextAreaElement, etc.

# Using a type guard to solve the error

An alternative and much better approach is to use a type guard.

src/index.ts
// ๐Ÿ‘‡๏ธ const input: HTMLElement | null const input = document.getElementById('submit'); function example(el: Element) { return el; } if (input != null) { const el1: HTMLElement = input; const el2: Element = input; example(input); }
The code for this article is available on GitHub

The if statement serves as a type guard. We explicitly check if the input variable does not store a null value.

src/index.ts
// ๐Ÿ‘‡๏ธ const input: HTMLElement | null const input = document.getElementById('submit'); // ๐Ÿ‘‰๏ธ input has type HTMLElement or null here if (input != null) { // ๐Ÿ‘‰๏ธ input has type HTMLElement here const el1: HTMLElement = input; const el2: Element = input; example(input); } function example(el: Element) { return el; }

TypeScript knows that the input variable has a type of HTMLElement in the if block and allows us to directly assign it to the el1 and el2 variables.

# Argument of type 'HTMLElement' not assignable to type in TS

Use a type assertion to solve the "Argument of type 'HTMLElement' is not assignable to parameter of type" error.

The types of the passed-in argument and the expected parameter have to be compatible.

argument type htmlelement not assignable parameter

Here are 2 examples of how the error occurs.

index.ts
const element = document.getElementById('example') as HTMLElement; function example1(el: HTMLInputElement) { return el; } // โ›”๏ธ Argument of type 'HTMLElement' is not assignable // to parameter of type 'HTMLInputElement'. example1(element); // ----------------------------------------------- function example2(el: HTMLCanvasElement) { return el; } // โ›”๏ธ Argument of type 'HTMLElement' is not assignable // to parameter of type 'HTMLCanvasElement'. example2(element);

The reason the error occurs in the first example is that the function expects a parameter of type HTMLInputElement and we're passing it a parameter of type HTMLElement.

In the second example, the function expects a parameter of type HTMLCanvasElement and we're passing it a parameter of type HTMLElement.

# Use a type assertion to solve the error

We can use a type assertion to solve the error.

index.ts
const element = document.getElementById('example') as HTMLElement; function example1(el: HTMLInputElement) { return el; } example1(element as HTMLInputElement); // ๐Ÿ‘ˆ๏ธ type assertion function example2(el: HTMLCanvasElement) { return el; } example2(element as HTMLCanvasElement); // ๐Ÿ‘ˆ๏ธ type assertion
The code for this article is available on GitHub
You have to use the specific parameter type that is mentioned in your error message.

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 the element variable stores a value of a specific type and not to worry about it.

The type you have to use in the type assertion is the type of function parameter.

The cause of the "Argument of type 'HTMLElement' is not assignable to parameter of type" error is that we are passing an argument of type HTMLElement to a function that has a parameter of a different type.

You could also use a type assertion when selecting the element.

index.ts
// ๐Ÿ‘‡๏ธ use type assertion here const element = document.getElementById('example') as HTMLInputElement; function example1(el: HTMLInputElement) { return el; } example1(element);

We typed the element variable as an HTMLInputElement element, which is the type the example1 function expects.

When calling a function, we have to make sure the type of the passed-in argument is compatible with the type of the expected parameter.

# Widen the parameter type with a union

Alternatively, you can widen the type of the function's parameter using a union type.

src/index.ts
const element = document.getElementById('example') as HTMLElement; function example1(el: HTMLInputElement | HTMLElement) { return el; } example1(element);
The code for this article is available on GitHub

The example function expects a parameter of type HTMLInputElement or HTMLElement, so passing it an argument of type HTMLElement satisfies the expected parameter type.

# (React) Argument type 'HTMLElement or null' not assignable to parameter type 'Element or DocumentFragment'

Use a non-null assertion or a type assertion to solve the React.js error "Argument of type 'HTMLElement | null' is not assignable to parameter of type 'Element | DocumentFragment'", e.g. const root = createRoot(rootElement!).

argument type htmlelement or null not assignable

Here is an example of how the error occurs.

index.tsx
import App from './App'; import {StrictMode} from 'react'; import {createRoot} from 'react-dom/client'; const rootElement = document.getElementById('root'); // โ›”๏ธ Argument of type 'HTMLElement | null' is not // assignable to parameter of type 'Element | DocumentFragment'. // Type 'null' is not assignable to type 'Element | DocumentFragment'.ts(2345) const root = createRoot(rootElement); root.render( <StrictMode> <App /> </StrictMode>, );

The issue here is that the return type of the document.getElementById method is HTMLElement | null.

If the provided ID does not exist in the DOM, the method returns null.

On the other hand, the expected parameter type of the createRoot method is Element | DocumentFragment, so there is a mismatch between the provided argument type and the expected parameter type.

One way to solve the error is to use the non-null (!) assertion operator.

index.tsx
import App from './App'; import {StrictMode} from 'react'; import {createRoot} from 'react-dom/client'; const rootElement = document.getElementById('root'); // ๐Ÿ‘‡๏ธ non-null (!) assertion const root = createRoot(rootElement!); root.render( <StrictMode> <App /> </StrictMode>, );
The non-null (!) assertion operator removes null and undefined from a type without doing any explicit type checking.

When you use this approach, you basically tell TypeScript that the rootElement variable will never be null or undefined. So, the rootElement variable becomes of type HTMLElement instead of HTMLElement | null.

Alternatively, you can use a simple type assertion.

index.tsx
import App from './App'; import {StrictMode} from 'react'; import {createRoot} from 'react-dom/client'; const rootElement = document.getElementById('root'); // ๐Ÿ‘‡๏ธ use type assertion const root = createRoot(rootElement as Element); root.render( <StrictMode> <App /> </StrictMode>, );

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

We are effectively telling TypeScript that the rootElement variable stores a value of type Element and not to worry about it.

We determined the correct type from the error message: "Argument of type 'HTMLElement | null' is not assignable to parameter of type 'Element | DocumentFragment'".

With this error message TypeScript tells us: The function's expected parameter type is Element | DocumentFragment, but you are calling the function with an argument of type HTMLElement | null.

The types are not compatible because the argument type is possibly null.

To solve the error, we have to make the passed-in argument and the expected parameter types are compatible.

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

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.

Copyright ยฉ 2024 Borislav Hadzhiev