Last updated: Jan 15, 2023
Reading timeยท7 min
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.
This is the HTML code for the examples.
<!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.
// ๐๏ธ 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 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.
input
variable might have a value of null
which is not compatible with the type of the el1
variable which only expects an HTMLElement
.Here are a couple of examples of how you can solve the error.
// ๐๏ธ 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
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
.
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.
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
Type assertions are used when we have information about the type of a value that TypeScript can't know about.
el1
will be an HTMLElement
and not to worry about it.You can also use a type assertion directly when selecting the element.
// ๐๏ธ 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.
An alternative and much better approach is to use a type guard.
// ๐๏ธ 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 if
statement serves as a type guard. We explicitly check if the input
variable does not store a null
value.
// ๐๏ธ 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.
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.
Here are 2 examples of how the error occurs.
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
.
We can use a type assertion to solve the error.
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
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 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.
// ๐๏ธ 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.
Alternatively, you can widen the type of the function's parameter using a union type.
const element = document.getElementById('example') as HTMLElement; function example1(el: HTMLInputElement | HTMLElement) { return el; } example1(element);
The example function expects a parameter of type HTMLInputElement
or
HTMLElement
, so passing it an argument of type HTMLElement
satisfies the
expected parameter type.
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!)
.
Here is an example of how the error occurs.
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
.
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.
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>, );
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.
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'".
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.
You can learn more about the related topics by checking out the following tutorials: