头图

The text starts here~

Overview

When we try to access the value property on an element of type HTMLElement , the error "Property 'value' does not exist on type 'HTMLElement'" is generated. To resolve the error, use a type assertion to assert the element type as HTMLInputElement before accessing the property.

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

Here is an example to show how the error occurs.

 // App.tsx

import {useEffect} from 'react';

export default function App() {
  useEffect(() => {
    const input = document.getElementById('message');

    // ⛔️ Property 'value' does not exist on type 'HTMLElement'.ts(2339)
    console.log(input?.value);
  }, []);

  return (
    <div>
      <input id="message" defaultValue="Initial value" />
    </div>
  );
}

The reason we get the error is because, the type returned by the document.getElementById method is HTMLElement | null and the value property does not exist on the type HTMLElement .

type assertion

To resolve the error, use a type assertion to assert the element type as HTMLInputElement (or HTMLTextAreaElement if you use the textarea element type).

 import {useEffect} from 'react';

export default function App() {
  useEffect(() => {
    // ✅ type element as HTMLInputElement
    const input = document.getElementById('message') as HTMLInputElement;

    console.log(input?.value); // 👉️ "Initial value"
  }, []);

  return (
    <div>
      <input id="message" defaultValue="Initial value" />
    </div>
  );
}

You can also use a type assertion inline, just before accessing the value property.

 // App.tsx

import {useEffect} from 'react';

export default function App() {
  useEffect(() => {
    // 👇️ inline type assertion
    const value = (document.getElementById('message') as HTMLInputElement).value;

    console.log(value);
  }, []);

  return (
    <div>
      <input id="message" defaultValue="Initial value" />
    </div>
  );
}

Type assertions are used when we have type information for a value, but TypeScript has no way of knowing it.

We're effectively telling TypeScript that the input variable stores a HTMLInputElement , don't worry about it.

If you were using a textarea element, you would use the HTMLTextAreaElement type instead.

union type

If you want more precise control over the type, you can use a union type to set the type to HTMLInputElement | null .

 // App.tsx

import {useEffect} from 'react';

export default function App() {
  useEffect(() => {
    // ✅ type element as HTMLInputElement | null
    const input = document.getElementById('message') as HTMLInputElement | null;

    console.log(input?.value); // 👉️ "Initial value"
  }, []);

  return (
    <div>
      <input id="message" defaultValue="Initial value" />
    </div>
  );
}

HTMLInputElement | null type is correct because the document.getElementById() method returns a null value if the element with the provided id does not exist in the DOM.

Note that we use the optional chaining ( ?. ) operator to short-circuit the operation if the reference is null ( null or undefined ).

In other words, if the input variable stored a null value, we would not have attempted to access the property of null and would have gotten a runtime error.

type guard

You can also use a simple if statement as a type guard to ensure that the input variable does not store a null value.

 // App.tsx

import {useEffect} from 'react';

export default function App() {
  useEffect(() => {
    const input = document.getElementById('message') as HTMLInputElement | null;

    if (input != null) {
      console.log(input.value); // 👉️ "Initial value"
    }
  }, []);

  return (
    <div>
      <input id="message" defaultValue="Initial value" />
    </div>
  );
}
TypeScript知道input变量在if块中的类型是HTMLInputElement ,并允许我们直接访问其value

It is always a best practice to include null in the type assertion, because if the provided element of ---670383ebc2670bab5354a93bf2b2189e id is not found, the getElementById method will return null .


chuck
300 声望41 粉丝