React监听ESC关闭模态框的handleEscClose函数TypeScript类型错误求解
原代码
useEffect(() => { const handleEscClose = (e: KeyboardEvent) => { if (e.key === 'Escape') changeVisibility(); }; if (isVisible) document.addEventListener('keydown', handleEscClose); return () => document.removeEventListener('keydown', handleEscClose); }, [changeVisibility, isVisible]);
问题描述
上述代码用于在模态框显示时监听ESC键以关闭模态框,但handleEscClose函数存在TypeScript类型问题,请问应为其添加何种类型?
错误信息
TS2769: No overload matches this call.
Overload 1 of 2, '(type: "keydown", listener: (this: Document, ev: KeyboardEvent) => any, options?: boolean | AddEventListenerOptions | undefined): void', gave the following error.
Argument of type '(e: KeyboardEvent) => void' is not assignable to parameter of type '(this: Document, ev: KeyboardEvent) => any'.
Types of parameters 'e' and 'ev' are incompatible.
Type 'KeyboardEvent' is not assignable to type 'KeyboardEvent'.
Overload 2 of 2, '(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void', gave the following error.
Argument of type '(e: KeyboardEvent) => void' is not assignable to type 'EventListenerOrEventListenerObject'.
解决方案
这个错误是因为TypeScript无法识别你使用的KeyboardEvent是DOM环境中的标准事件类型(可能存在类型作用域冲突或自定义同名类型),只需明确指定参数为全局DOM的KeyboardEvent类型即可解决:
useEffect(() => { // 明确使用globalThis下的KeyboardEvent类型 const handleEscClose = (e: globalThis.KeyboardEvent) => { if (e.key === 'Escape') changeVisibility(); }; if (isVisible) document.addEventListener('keydown', handleEscClose); return () => document.removeEventListener('keydown', handleEscClose); }, [changeVisibility, isVisible]);
另一种可选方案是使用EventListener类型定义函数,再通过类型断言判断事件类型:
useEffect(() => { const handleEscClose: EventListener = (e) => { if ((e as KeyboardEvent).key === 'Escape') changeVisibility(); }; if (isVisible) document.addEventListener('keydown', handleEscClose); return () => document.removeEventListener('keydown', handleEscClose); }, [changeVisibility, isVisible]);
推荐第一种方案,无需类型断言,类型更严谨。
内容的提问来源于stack exchange,提问作者pvp11

