头图

正文从这开始~

总览

当我们试图访问一个类型为HTMLElement的元素上的value属性时,会产生"Property 'value' does not exist on type 'HTMLElement'"错误。为了解决该错误,在访问属性之前,使用类型断言将元素类型断言为HTMLInputElement

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

这里有个示例用来展示错误是如何发生的。

// 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>
  );
}

我们得到错误的原因是因为,document.getElementById方法返回的类型为HTMLElement | null ,并且value属性不存在于HTMLElement类型上。

类型断言

为了解决该错误,使用类型断言将元素类型断言为HTMLInputElement(或者HTMLTextAreaElement,如果你使用textarea元素键入)。

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>
  );
}

你也可以在内联中使用一个类型断言,就在访问值属性之前。

// 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>
  );
}

当我们拥有一个值的类型信息,但是TypeScript无从得知时,就会使用类型断言。

我们有效地告诉TypeScript,input变量存储了一个HTMLInputElement,不用担心它。

如果你正在使用一个textarea元素,你将使用HTMLTextAreaElement类型来代替。

联合类型

如果你想更精确地控制类型,你可以使用一个联合类型来设置类型为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类型是正确的,因为如果提供id的元素不存在于DOM中,document.getElementById()方法就会返回一个null值。

需要注意的是,我们使用了可选链(?.)操作符来短路运算,如果引用是空值的话(null或者undefined)。

换句话说,如果input变量存储了一个null值,我们就不会试图访问null的属性,而得到一个运行时错误。

类型守卫

你也可以使用一个简单的if语句作为类型守卫,以确保input变量不存储一个null值。

// 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属性。

在类型断言中包含null总是一种最佳实践,因为如果没有找到所提供的id的元素,getElementById方法将返回null


chuck
300 声望41 粉丝