正文从这开始~

总览

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

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

  1. // App.tsx
  2. import {useEffect} from 'react';
  3. export default function App() {
  4. useEffect(() => {
  5. const input = document.getElementById('first_name');
  6. // ️ Property 'value' does not exist on type 'HTMLElement'.ts(2339)
  7. console.log(input?.value);
  8. // -----------------------------------------------------------------
  9. const link = document.getElementById('link');
  10. // ️ Property 'href' does not exist on type 'HTMLElement'.ts(2339)
  11. console.log(link?.href);
  12. // -----------------------------------------------------------------
  13. const button = document.getElementById('btn');
  14. if (button != null) {
  15. // ️ Property 'disabled' does not exist on type 'HTMLElement'.ts(2339)
  16. button.disabled = true;
  17. }
  18. }, []);
  19. return (
  20. <div>
  21. <input
  22. id="first_name"
  23. type="text"
  24. name="first_name"
  25. defaultValue="Initial Value"
  26. />
  27. <a id="link" href="<https://google.com>" target="_blank" rel="noreferrer">
  28. Open Google
  29. </a>
  30. <button id="btn">Submit</button>
  31. </div>
  32. );
  33. }

产生错误的原因是,document.getElementById方法的返回类型是HTMLElement | null,但是我们试图访问的属性不存在于HTMLElement 类型。

类型断言

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

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

  1. import {useEffect} from 'react';
  2. export default function App() {
  3. useEffect(() => {
  4. // type elements correctly via type assertions
  5. const input = document.getElementById('first_name') as HTMLInputElement;
  6. console.log(input?.value);
  7. const link = document.getElementById('link') as HTMLAnchorElement;
  8. console.log(link?.href);
  9. const button = document.getElementById('btn') as HTMLButtonElement;
  10. if (button != null) {
  11. button.disabled = true;
  12. }
  13. }, []);
  14. return (
  15. <div>
  16. <input
  17. id="first_name"
  18. type="text"
  19. name="first_name"
  20. defaultValue="Initial Value"
  21. />
  22. <a id="link" href="<https://google.com>" target="_blank" rel="noreferrer">
  23. Open Google
  24. </a>
  25. <button id="btn">Submit</button>
  26. </div>
  27. );
  28. }

类型断言被用于我们知道值的类型信息,但是TypeScript却不知道的时候。

我们明确的告诉TypeScript,input变量上存储了HTMLInputElement ,并让TS不要担心。

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

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

  1. import {useEffect} from 'react';
  2. export default function App() {
  3. useEffect(() => {
  4. const value = (document.getElementById('first_name') as HTMLInputElement).value;
  5. console.log(value);
  6. }, []);
  7. return (
  8. <div>
  9. <input
  10. id="first_name"
  11. type="text"
  12. name="first_name"
  13. defaultValue="Initial Value"
  14. />
  15. <a id="link" href="<https://google.com>" target="_blank" rel="noreferrer">
  16. Open Google
  17. </a>
  18. <button id="btn">Submit</button>
  19. </div>
  20. );
  21. }

如果你只需要访问属性一次,并且不希望将元素分配给变量,那么内联类型声明可以完成这项工作。

如果你想更精确地处理元素的类型,可以使用联合类型将类型声明为HTML***Element | null

  1. import {useEffect} from 'react';
  2. export default function App() {
  3. useEffect(() => {
  4. const input = document.getElementById(
  5. 'first_name',
  6. ) as HTMLInputElement | null;
  7. console.log(input?.value);
  8. const link = document.getElementById('link') as HTMLAnchorElement | null;
  9. console.log(link?.href);
  10. const button = document.getElementById('btn') as HTMLButtonElement | null;
  11. if (button != null) {
  12. button.disabled = true;
  13. }
  14. }, []);
  15. return (
  16. <div>
  17. <input
  18. id="first_name"
  19. type="text"
  20. name="first_name"
  21. defaultValue="Initial Value"
  22. />
  23. <a id="link" href="<https://google.com>" target="_blank" rel="noreferrer">
  24. Open Google
  25. </a>
  26. <button id="btn">Submit</button>
  27. </div>
  28. );
  29. }

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

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

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

总结

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

React报错之Property 'X' does not exist on type 'HTMLElement'的更多相关文章

  1. React报错之Property 'value' does not exist on type 'HTMLElement'

    正文从这开始~ 总览 当我们试图访问一个类型为HTMLElement的元素上的value属性时,会产生"Property 'value' does not exist on type 'HT ...

  2. React报错之Property 'value' does not exist on type EventTarget

    正文从这开始~ 总览 当event参数的类型不正确时,会产生"Property 'value' does not exist on type EventTarget"错误.为了解决 ...

  3. React报错之Parameter 'props' implicitly has an 'any' type

    正文从这开始~ 总览 当我们没有为函数组件或者类组件的props声明类型,或忘记为React安装类型声明文件时,会产生"Parameter 'props' implicitly has an ...

  4. React报错之Parameter 'event' implicitly has an 'any' type

    正文从这开始~ 总览 当我们不在事件处理函数中为事件声明类型时,会产生"Parameter 'event' implicitly has an 'any' type"错误.为了解决 ...

  5. 解决TS报错Property 'style' does not exist on type 'Element'

    在使用queryselector获取一个dom元素,编译时却报错说property 'style' does not exist on type 'element'. 原因:这是typescript的 ...

  6. react 报错的堆栈处理

    react报错 Warning: You cannot PUSH the same path using hash history 在Link上使用replace 原文地址https://reactt ...

  7. elasticsearch查询:启动项目报错No property ... found for...Did you mean '...'?

    网上找的案例是: 实体类字段定义:private String sku_no;dao中接口名定义:Goods findBySkuNo(String skuNo);spring-data按照接口方法定义 ...

  8. react中使用typescript时,error: Property 'setState' does not exist on type 'Home'

    问题描述: 我在react中用typescript时,定义一个Home组件,然后在组件里用setState时会有这样一个报错:(如图)Property 'setState' does not exis ...

  9. notification 报错the method build() is undefined for the type Notificatin.Builder

    notification 报错the method build() is undefined for the type Notificatin.Builder 这事api版本号太低导致的 Notifi ...

随机推荐

  1. Redis 的数据过期了就会马上删除么?

    码哥,当 key 达到过期时间,Redis 就会马上删除么? 先说结论,并不会立马删除,Redis 有两种删除过期数据的策略: 定期选取部分数据删除: 惰性删除: 该命令在 Redis 2.4 版本, ...

  2. # k8s-jenkins在kubernetes中持续部署

    k8s-jenkins在kubernetes中持续部署 1. k8s-jenkins在kubernetes中持续部署 Kubernetes Continuous Deploy插件:用于将资源配置部署到 ...

  3. Css实例之信息提交

    代码实例: <!DOCTYPE html><html><head><meta charset="UTF-8"><title&g ...

  4. MySQL的Explain总结

    Explain简介 MySQL优化器在基于成本的计算和基于规则的SQL优化会生成一个所谓的执行计划,我们就可以使用执行计划查看MySQL对该语句具体的执行方式. 介绍这个好啰嗦就是了,我们可以通过这个 ...

  5. BERT的优化演进方法汇总(持续更新)

    模型结构演进 本文以演进方向和目的为线索梳理了一些我常见到但不是很熟悉的预训练语言模型,首先来看看"完全版的BERT":RoBERTa: A Robustly Optimized ...

  6. 一个ES设置操作引发的“血案”

    背景说明 ES版本 7.1.4 在ES生产环境中增加字段,一直提示Setting index.mapper.dynamic was removed after version 6.0.0错误.但是我只 ...

  7. 第三章、DNS域名解析服务

    DNS 1DNS简介 域名系统(英文:Domain Name System,缩写:DNS)是互联网的一项服务.它作为将域名和 IP 地址相互映射的一个分布式数据库,能够使人更方便地访问互联网.DNS ...

  8. Docker-配置华为云加速

    到网址点击立即使用 https://www.huaweicloud.com/intl/zh-cn/product/swr.html 登录后进入镜像服务 按要求操作即可 相关命令 vi /etc/doc ...

  9. RocketMQ消息的顺序与重复

    1.如何保证消息的顺序 原因:生产者将消息发给topic,topic分发给不同的队列再给多个消费者并发消费,难以保证顺序. 方案:topic和队列之间加入MessageQueueSelector.将一 ...

  10. ASP.NET MVC的核心-Controller(控制器)

    "每一个请求都必须通过Controller处理,然而其中有些请求是不需要模型和视图的" MVC框架规定带Controller后缀的类称为所谓的"控制器",在xx ...