Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React onclick Argument of type 'EventTarget' is not assignable to parameter of type 'Node'

I import MouseEvent from react

import { MouseEvent } from 'react';

Use MouseEvent in the following

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

I listen to my closeSelectBox

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

  useEffect(() => {
    document.addEventListener("click", closeSelectBox);
    return () => {
      document.removeEventListener("click", closeSelectBox);
    };
  }, [])

searchOptionWrapRef is a div

const searchOptionWrapRef = useRef<HTMLDivElement>(null);

<div ref={searchOptionWrapRef}/>

But I get the following error

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.

How do I resolve this type error without using any in place of MouseEvent?

>Solution :

The event interfaces exported by React are for React event handler props, not addEventListener handlers. For those, don’t import MouseEvent from React and you’ll get the DOM global interface for it instead, which works with addEventListener. And yes, it’s confusing. 🙂

But the second issue (which actually may be your main issue) is that the DOM global MouseEvent defines target as an EventTarget, not as a Node. In your case, it’ll always be a Node (specifically, an Element), but that’s how the DOM type is defined. To deal with that, you have at least two choices:

Purist

You could go really purist (I do) and use a type assertion function to assert that target is a 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);
    }
};

Playground link

Concise and Pragmatic

You know that target is a Node and isn’t null, so you could use a type assertion (target as Node):

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

Playground link

I don’t like type assertions that aren’t checked at runtime (which is what a type assertion function like assertIsNode does), so I’d probably go with the first approach. But in limited situations where you’re sure about it, you might consider one.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading