• React报错之Property 'X' does not exist on type 'HTMLElement'


    正文从这开始~

    总览

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

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

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

    // 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="" target="_blank" rel="noreferrer">
            Open Google
          a>
    
          <button id="btn">Submitbutton>
        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="" target="_blank" rel="noreferrer">
            Open Google
          a>
    
          <button id="btn">Submitbutton>
        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="" target="_blank" rel="noreferrer">
            Open Google
          a>
    
          <button id="btn">Submitbutton>
        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="" target="_blank" rel="noreferrer">
            Open Google
          a>
    
          <button id="btn">Submitbutton>
        div>
      );
    }
    
    折叠

    HTML***Element 或者null 类型是最准确的类型,因为如果DOM元素上不存在id属性,那么document.getElementById()将会返回null

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

    或者,你可以使用简单的if语句作为类型守卫,就像我们对button处理的那样。

    总结

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

  • 相关阅读:
    springcloud-config git配置源加载(部署公钥问题)
    关于2023年的裸辞对话
    服装品牌如何成为“数字化的头号玩家”?这个案例不容错过!
    2022牛客暑期多校训练营7(总结+补题)
    Redis 常见问题
    算法刷题日志——dp
    LeetCode 63. 不同路径 II
    [ vulhub漏洞复现篇 ] struts2远程代码执行漏洞s2-046(CVE-2017-5638)
    线程池交叉引用问题纠正
    技术与安全的交织
  • 原文地址:https://www.cnblogs.com/chuckQu/p/16538404.html