TypeScript中MediaQueryListEvent回调无法赋值给Event类型参数如何解决
报错原因
- TypeScript函数参数遵循逆变规则:虽然
MediaQueryListEvent是Event的子类型,但(e: MediaQueryListEvent) => void并不是(e: Event) => void的子类型。你定义的useEventListener硬编码了回调参数为Event类型、事件名只能是WindowEventMap的键,无法适配MediaQueryList的change事件对应的MediaQueryListEvent类型,因此触发类型不兼容报错。
解决方案
最优方案:重写为泛型版useEventListener
改造后的Hook支持根据传入的事件目标类型,自动推导对应的事件名和回调参数类型,适用性更广:
import { useRef, useEffect } from 'react'; // 双泛型分别约束事件目标类型、对应事件名,保证类型精准匹配 const useEventListener = < E extends EventTarget, K extends keyof E['EventMap'] >( event: K, callback: (e: E['EventMap'][K]) => void, element: E | null = window as E ) => { const callbackRef = useRef(callback); // 同步最新回调避免闭包问题 useEffect(() => { callbackRef.current = callback; }, [callback]); useEffect(() => { if (!element) return; const handler = (e: Event) => callbackRef.current(e as E['EventMap'][K]); element.addEventListener(event, handler); return () => element.removeEventListener(event, handler); }, [event, element]); };
改造完成后无需修改useMediaQuery的原有逻辑,类型报错会自动消失,同时能获得完整的类型提示。
临时解决方案:类型断言
如果不想修改原有useEventListener的实现,可以在回调内对事件参数做类型断言绕开校验:
useEventListener( "change", (e) => setIsMatching((e as MediaQueryListEvent).matches), mediaQueryList )
内容的提问来源于stack exchange,提问作者Andrea Costanzo
相关产品推荐
相关产品推荐

