1
头图

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.

property-value-does-not-exist-on-type-htmlelement.webp

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 that input stores HTMLInputElement 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 .


chuck
303 声望41 粉丝