The text starts here~
Overview
In React, Property 'X' does not exist on type 'HTMLElement' error occurs when we try to access a property that does not exist on an element of type HTMLElement
. To work around this error, use a type assertion to correctly type declare the element before accessing the property.
Here are three examples to show how errors can occur.
// App.tsx
import {useEffect} from 'react';
export default function App() {
useEffect(() => {
const input = document.getElementById('first_name');
// ⛔️ Property 'value' does not exist on type 'HTMLElement'.ts(2339)
console.log(input?.value);
// -----------------------------------------------------------------
const link = document.getElementById('link');
// ⛔️ Property 'href' does not exist on type 'HTMLElement'.ts(2339)
console.log(link?.href);
// -----------------------------------------------------------------
const button = document.getElementById('btn');
if (button != null) {
// ⛔️ Property 'disabled' does not exist on type 'HTMLElement'.ts(2339)
button.disabled = true;
}
}, []);
return (
<div>
<input
id="first_name"
type="text"
name="first_name"
defaultValue="Initial Value"
/>
<a id="link" href="<https://google.com>" target="_blank" rel="noreferrer">
Open Google
</a>
<button id="btn">Submit</button>
</div>
);
}
The reason for the error is that the return type of the --- document.getElementById
method is HTMLElement | null
, but the property we are trying to access does not exist of type HTMLElement
.
type assertion
To resolve this error, use type assertions to correctly type declarations for elements. HTMLInputElement
, HTMLButtonElement
, HTMLAnchorElement
, HTMLImageElement
, HTMLDivElement
, HTMLTextAreaElement
Wait. It depends on the element you're dealing with.
These types are always named HTML***Element
. Once you start typing HTML…
your IDE will autocomplete for you.
import {useEffect} from 'react';
export default function App() {
useEffect(() => {
// ✅ type elements correctly via type assertions
const input = document.getElementById('first_name') as HTMLInputElement;
console.log(input?.value);
const link = document.getElementById('link') as HTMLAnchorElement;
console.log(link?.href);
const button = document.getElementById('btn') as HTMLButtonElement;
if (button != null) {
button.disabled = true;
}
}, []);
return (
<div>
<input
id="first_name"
type="text"
name="first_name"
defaultValue="Initial Value"
/>
<a id="link" href="<https://google.com>" target="_blank" rel="noreferrer">
Open Google
</a>
<button id="btn">Submit</button>
</div>
);
}
Type assertions are used when we know the type information of a value, but TypeScript doesn't.
We explicitly tell TypeScript thatinput
storesHTMLInputElement
955712af2ea7895c7a05de980a96ba99--- in the variable, and tell TS not to worry.
Similarly, we declare the link
variable type as HTMLAnchorElement
and the btn
variable type as HTMLButtonElement
.
You can use type assertions inline before accessing a property.
import {useEffect} from 'react';
export default function App() {
useEffect(() => {
const value = (document.getElementById('first_name') as HTMLInputElement).value;
console.log(value);
}, []);
return (
<div>
<input
id="first_name"
type="text"
name="first_name"
defaultValue="Initial Value"
/>
<a id="link" href="<https://google.com>" target="_blank" rel="noreferrer">
Open Google
</a>
<button id="btn">Submit</button>
</div>
);
}
If you only need to access the property once, and don't want to assign the element to a variable, then an inline type declaration can do the job.
If you want to be more precise about the type of the elements, you can use a union type to declare the type as HTML***Element | null
.
import {useEffect} from 'react';
export default function App() {
useEffect(() => {
const input = document.getElementById(
'first_name',
) as HTMLInputElement | null;
console.log(input?.value);
const link = document.getElementById('link') as HTMLAnchorElement | null;
console.log(link?.href);
const button = document.getElementById('btn') as HTMLButtonElement | null;
if (button != null) {
button.disabled = true;
}
}, []);
return (
<div>
<input
id="first_name"
type="text"
name="first_name"
defaultValue="Initial Value"
/>
<a id="link" href="<https://google.com>" target="_blank" rel="noreferrer">
Open Google
</a>
<button id="btn">Submit</button>
</div>
);
}
HTML***Element
or null
type is the most accurate, because if the id
attribute does not exist on the DOM element, then document.getElementById()
will return null
.
You can use the optional chaining operator ( ?.
) to short-circuit before accessing properties if the reference is null ( null
or undefined
).
Alternatively, you can use a simple if
statement as a type guard, as we did with button
.
Summarize
Best practice is to include null
in the type assertion. Because if the id
attribute is not provided on the element, then the getElementById
method will return null
.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。