I'm trying to create a re-usable custom hook that enables a user close the menu when they either click off the node or press escape.
I've never used Typescript before and I want to destructure the event object rather than use it directly, e.g. event.type, and create type declarations for the object keys.
import * as React from "react";
interface IProps {
type: React.MouseEvent<string> | React.KeyboardEvent<string>;
target: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>;
key?: React.KeyboardEvent<string>;
}
/**
* Allows you to close a menu when user clicks outside of the nodes family tree.
*/
function useCloseMenu(
ref: React.MutableRefObject<any>,
isMenuOpen: boolean,
callback: () => void
): void {
React.useEffect(() => {
function handleUserEvent({ type, target, key = null }: IProps): void {
switch (type) {
case "click":
if (!ref.current?.contains(target) && isMenuOpen) {
callback();
}
case "keydown":
// "Esc" is an IE/Edge specific value
if (key === ("Escape" || "Esc") && isMenuOpen) {
callback();
}
}
}
document.addEventListener("click", handleUserEvent);
document.addEventListener("keydown", handleUserEvent);
return () => {
document.removeEventListener("click", handleUserEvent);
document.addEventListener("keydown", handleUserEvent);
};
}, [isMenuOpen]);
}
export default useCloseMenu;
use-close-menu.tsx:21:14 - error TS2678: Type 'string' is not comparable to type 'MouseEvent<string, MouseEvent> | KeyboardEvent<string>'.
21 case "click":
~~~~~~~
use-close-menu.tsx:26:14 - error TS2678: Type 'string' is not comparable to type 'MouseEvent<string, MouseEvent> | KeyboardEvent<string>'.
26 case "keydown":
~~~~~~~~~
use-close-menu.tsx:28:15 - error TS2367: This condition will always return 'false' since the types 'KeyboardEvent<string>' and 'string' have no overlap.
28 if (key === ("Escape" || "Esc") && isMenuOpen) {
~~~~~~~~~~~~~~~~~~~~~~~~~~~
use-close-menu.tsx:34:40 - error TS2769: No overload matches this call.
Overload 1 of 2, '(type: "click", listener: (this: Document, ev: MouseEvent) => any, options?: boolean | AddEventListenerOptions): void', gave the following error.
Argument of type '({ type, target, key }: IProps) => void' is not assignable to parameter of type '(this: Document, ev: MouseEvent) => any'.
Types of parameters '__0' and 'ev' are incompatible.
Type 'MouseEvent' is not assignable to type 'IProps'.
Types of property 'type' are incompatible.
Type 'string' is not assignable to type 'MouseEvent<string, MouseEvent> | KeyboardEvent<string>'.
Overload 2 of 2, '(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void', gave the following error.
Argument of type '({ type, target, key }: IProps) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'.
Type '({ type, target, key }: IProps) => void' is not assignable to type 'EventListener'.
Types of parameters '__0' and 'evt' are incompatible.
Type 'Event' is not assignable to type 'IProps'.
Types of property 'type' are incompatible.
Type 'string' is not assignable to type 'MouseEvent<string, MouseEvent> | KeyboardEvent<string>'.
34 document.addEventListener("click", handleUserEvent);
~~~~~~~~~~~~~~~
use-close-menu.tsx:35:42 - error TS2769: No overload matches this call.
Overload 1 of 2, '(type: "keydown", listener: (this: Document, ev: KeyboardEvent) => any, options?: boolean | AddEventListenerOptions): void', gave the following error.
Argument of type '({ type, target, key }: IProps) => void' is not assignable to parameter of type '(this: Document, ev: KeyboardEvent) => any'.
Types of parameters '__0' and 'ev' are incompatible.
Type 'KeyboardEvent' is not assignable to type 'IProps'.
Types of property 'type' are incompatible.
Type 'string' is not assignable to type 'MouseEvent<string, MouseEvent> | KeyboardEvent<string>'.
Overload 2 of 2, '(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void', gave the following error.
Argument of type '({ type, target, key }: IProps) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'.
Type '({ type, target, key }: IProps) => void' is not assignable to type 'EventListener'.
35 document.addEventListener("keydown", handleUserEvent);
~~~~~~~~~~~~~~~
use-close-menu.tsx:37:45 - error TS2769: No overload matches this call.
Overload 1 of 2, '(type: "click", listener: (this: Document, ev: MouseEvent) => any, options?: boolean | EventListenerOptions): void', gave the following error.
Argument of type '({ type, target, key }: IProps) => void' is not assignable to parameter of type '(this: Document, ev: MouseEvent) => any'.
Types of parameters '__0' and 'ev' are incompatible.
Type 'MouseEvent' is not assignable to type 'IProps'.
Overload 2 of 2, '(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void', gave the following error.
Argument of type '({ type, target, key }: IProps) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'.
Type '({ type, target, key }: IProps) => void' is not assignable to type 'EventListener'.
37 document.removeEventListener("click", handleUserEvent);
~~~~~~~~~~~~~~~
use-close-menu.tsx:38:44 - error TS2769: No overload matches this call.
Overload 1 of 2, '(type: "keydown", listener: (this: Document, ev: KeyboardEvent) => any, options?: boolean | AddEventListenerOptions): void', gave the following error.
Argument of type '({ type, target, key }: IProps) => void' is not assignable to parameter of type '(this: Document, ev: KeyboardEvent) => any'.
Overload 2 of 2, '(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void', gave the following error.
Argument of type '({ type, target, key }: IProps) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'.
Type '({ type, target, key }: IProps) => void' is not assignable to type 'EventListener'.
38 document.addEventListener("keydown", handleUserEvent);
~~~~~~~~~~~~~~~
Found 7 errors.
However, I'm going round in circles with TS error handling here. Can someone help me understand how to resolve these errors?
typeis an event object, not a string.