注释从这开始~

总览

在React中,当咱们试图拜访类型为HTMLElement 的元素上不存在的属性时,就会产生Property 'X' does not exist on type 'HTMLElement'谬误。为了解决该谬误,在拜访属性之前,应用类型断言来正确地类型申明元素。

这里有三个例子来展现谬误是如何产生的。

// App.tsximport {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>  );}

产生谬误的起因是,document.getElementById办法的返回类型是HTMLElement | null,然而咱们试图拜访的属性不存在于HTMLElement 类型。

类型断言

为了解决这个谬误,应用类型断言来为元素正确地进行类型申明。比如说,类型断言为HTMLInputElementHTMLButtonElementHTMLAnchorElementHTMLImageElementHTMLDivElementHTMLTextAreaElement等等。这取决于你所解决的元素。

这些类型始终命名为HTML***Element 。一旦你开始输出HTML…,你的IDE将会帮你主动补全。

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

类型断言被用于咱们晓得值的类型信息,然而TypeScript却不晓得的时候。

咱们明确的通知TypeScript,input变量上存储了HTMLInputElement ,并让TS不要放心。

同样的,咱们将link变量类型申明为HTMLAnchorElement,将btn变量类型申明为HTMLButtonElement

你能够在拜访一个属性之前,内联应用类型断言。

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

如果你只须要拜访属性一次,并且不心愿将元素调配给变量,那么内联类型申明能够实现这项工作。

如果你想更准确地解决元素的类型,能够应用联结类型将类型申明为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 或者null 类型是最精确的类型,因为如果DOM元素上不存在id属性,那么document.getElementById()将会返回null

你能够应用可选链操作符(?.)在拜访属性之前来进行短路运算,如果援用是空值(null或者undefined)的话。

或者,你能够应用简略的if语句作为类型守卫,就像咱们对button解决的那样。

总结

最佳实际是在类型断言中蕴含null 。因为如果元素下面不提供id属性,那么getElementById办法将会返回null