React onclick“EventTarget”类型的参数不可分配给“Node”类型的参数

dev*_*_el 34 typescript reactjs

MouseEvent从反应导入

import { MouseEvent } from 'react';
Run Code Online (Sandbox Code Playgroud)

MouseEvent在下面使用

  const closeSelectBox = (e: MouseEvent): void => {
    if (!searchOptionWrapRef.current?.contains(e.target)) {
      setOpenSelectBox(false)
    }
  };
Run Code Online (Sandbox Code Playgroud)

我听我的closeSelectBox

  useEffect(() => {
    document.addEventListener("click", closeSelectBox);
    return () => {
      document.removeEventListener("click", closeSelectBox);
    };
  }, [])
Run Code Online (Sandbox Code Playgroud)

searchOptionWrapRef是一个div

const searchOptionWrapRef = useRef<HTMLDivElement>(null);

<div ref={searchOptionWrapRef}/>
Run Code Online (Sandbox Code Playgroud)

但我收到以下错误

Argument of type 'EventTarget' is not assignable to parameter of type 'Node'.
  Type 'EventTarget' is missing the following properties from type 'Node': baseURI, childNodes, firstChild, isConnected, and 43 more.
Run Code Online (Sandbox Code Playgroud)

如何在不使用anyin 代替 的情况下解决此类型错误MouseEvent

T.J*_*der 63

React 导出的事件接口用于 React 事件处理程序 props,而不是addEventListener处理程序。对于这些,不要从 React导入MouseEvent,您将获得它的 DOM 全局接口,该接口适用于addEventListener. 是的,这很令人困惑。:-)

但第二个问题(实际上可能是您的主要问题)是 DOM 全局MouseEvent定义target为 an EventTarget,而不是Node. 在你的例子中,它总是一个Node(具体来说,一个Element),但这就是 DOM 类型的定义方式。为了解决这个问题,你至少有两个选择:

纯粹主义者

你可以变得非常纯粹(我愿意)并使用类型断言函数来断言这target是一个Node

// In a utility library:
function assertIsNode(e: EventTarget | null): asserts e is Node {
    if (!e || !("nodeType" in e)) {
        throw new Error(`Node expected`);
    }
}

// And then in your component:
const closeSelectBox = ({target}: MouseEvent): void => {
    assertIsNode(target);
    if (!searchOptionWrapRef.current?.contains(target)) {
        setOpenSelectBox(false);
    }
};
Run Code Online (Sandbox Code Playgroud)

游乐场链接

简洁务实

知道targetaNode且不是null,因此您可以使用类型断言 ( target as Node):

const closeSelectBox = ({target}: MouseEvent): void => {
    if (!searchOptionWrapRef.current?.contains(target as Node)) {
        setOpenSelectBox(false);
    }
};
Run Code Online (Sandbox Code Playgroud)

游乐场链接

我不喜欢在运行时不检查的类型断言(这就是类型断言函数所做的assertIsNode),所以我可能会采用第一种方法。但在您确定的有限情况下,您可能会考虑这样做。


Dom*_*nic 6

您可以断言该实例属于ElementHTMLElement使用instanceof。该解决方案以最小的方式解决了运行时和编译时检查,而不会导致异常。

const closeSelectBox = (e: MouseEvent): void => {
  if (e.target instanceof HTMLElement && !searchOptionWrapRef.current?.contains(e.target)) {
    setOpenSelectBox(false)
  }
};
Run Code Online (Sandbox Code Playgroud)