You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React随机词汇替换TypeScript报错:Property 'dataset'不存在于EventTarget

解决TypeScript中EventTarget无dataset属性的报错

问题描述

我正在通过React解决JS问题学习React,编辑器抛出类型错误:

Error: Property 'dataset' does not exist on type 'EventTarget'.(2339)

但浏览器控制台无报错,相关代码如下:

import { FC } from 'react';

import './style.css';

export const App: FC<{ name: string }> = ({ name }) => {
  const buttons = document.querySelectorAll('button');
  const textarea = document.querySelector('textarea');
  const output = document.querySelector('.output');

  // flavours
  const flavours = {
    ninja: ['dojo', 'shogun', 'shinobi', 'samuri', 'shuriken'],
    pokemon: ['pika', 'pokeball', 'pokedex', 'evolve', 'ash', 'gym'],
    space: ['universe', 'galaxy', 'telescope', 'comet', 'stars'],
  };

  // functions
  const flavourize = (inputText, flavour) => {
    const textArray = inputText.split(' ');

    for (let i = 0; i < textArray.length; i++) {
      if (i % 3 === 0) {
        const random = Math.floor(Math.random() * flavour.length);
        textArray[i] = flavour[random];
      }
    }

    return textArray.join(' ');
  };

  const updateOutput = (text) => {
    output.textContent = text;
  };

  // event listener
  buttons.forEach((b) => {
    b.addEventListener('click', (e) => {
      e.preventDefault();
      if (textarea.value) {
        const f = e.target.dataset.flavour;
        const text = flavourize(textarea.value, flavours[f]);
        updateOutput(text);
      }
    });
  });

  return (
    <div>
      <h1>Hello {name}!</h1>
      <p>Start editing to see some magic happen :)</p>

      <form>
        <textarea></textarea>
        <div className="buttons">
          <p>Choose your theme:</p>
          <button data-flavour="ninja">Ninja</button>
          <button data-flavour="pokemon">Pokemon</button>
          <button data-flavour="space">Space</button>
        </div>
      </form>
    </div>
  );
};

报错原因

TypeScript对EventTarget的类型定义是通用的,它不包含dataset属性——因为EventTarget可以指向任何DOM元素甚至非DOM对象。但在浏览器运行时,e.target实际是HTMLButtonElement,确实拥有dataset属性,所以运行时不会报错,只有编辑器的类型检查会提示错误。

解决方案

方案1:类型断言(快速修复)

直接将e.target断言为HTMLButtonElement,明确告诉TypeScript这个目标元素是按钮,拥有dataset属性:

// 修改事件处理中的这一行
const f = (e.target as HTMLButtonElement).dataset.flavour;

方案2:改用React事件绑定(最佳实践)

原代码使用原生DOM查询和事件监听,不符合React的声明式编程模式。推荐直接在JSX中绑定事件,并用useRef获取DOM元素,同时通过函数参数传递主题类型,完全避免类型问题:

import { FC, useRef } from 'react';
import './style.css';

export const App: FC<{ name: string }> = ({ name }) => {
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const outputRef = useRef<HTMLDivElement>(null);

  const flavours = {
    ninja: ['dojo', 'shogun', 'shinobi', 'samuri', 'shuriken'],
    pokemon: ['pika', 'pokeball', 'pokedex', 'evolve', 'ash', 'gym'],
    space: ['universe', 'galaxy', 'telescope', 'comet', 'stars'],
  };

  const flavourize = (inputText: string, flavour: string[]) => {
    const textArray = inputText.split(' ');
    for (let i = 0; i < textArray.length; i++) {
      if (i % 3 === 0) {
        const random = Math.floor(Math.random() * flavour.length);
        textArray[i] = flavour[random];
      }
    }
    return textArray.join(' ');
  };

  const updateOutput = (text: string) => {
    if (outputRef.current) {
      outputRef.current.textContent = text;
    }
  };

  const handleButtonClick = (flavour: keyof typeof flavours) => (e: React.FormEvent) => {
    e.preventDefault();
    if (textareaRef.current?.value) {
      const text = flavourize(textareaRef.current.value, flavours[flavour]);
      updateOutput(text);
    }
  };

  return (
    <div>
      <h1>Hello {name}!</h1>
      <p>Start editing to see some magic happen :)</p>

      <form>
        <textarea ref={textareaRef}></textarea>
        <div className="buttons">
          <p>Choose your theme:</p>
          <button onClick={handleButtonClick('ninja')}>Ninja</button>
          <button onClick={handleButtonClick('pokemon')}>Pokemon</button>
          <button onClick={handleButtonClick('space')}>Space</button>
        </div>
        <div className="output" ref={outputRef}></div>
      </form>
    </div>
  );
};

这个方案的优点:

  • 遵循React声明式范式,避免直接操作DOM
  • 通过函数参数传递主题,类型安全,无需依赖dataset
  • 使用useRef获取DOM元素,TypeScript能正确推断元素类型

内容的提问来源于stack exchange,提问作者zi zi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 07:24:54