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
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
?
CodePudding user response:
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);
}
};
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);
}
};
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.