我正在尝试构建一个函数来添加一个事件侦听器,该监听器使用提供的事件名称来检查提供的处理程序函数是否处理正确的事件。考虑下面的代码片段。
(上下文:这是针对React钩子的,但问题是这样删除了React特定代码的类型记录类型。)
type Events = HTMLElementEventMap & WindowEventMap & DocumentEventMap;
type EventKey = keyof Events;
type ListenerElements = HTMLElement | Window | Document;
const useEventListener = <K extends EventKey>(
event: K,
handler: (event: Events[K]) => void,
element: ListenerElements = window
) => {
element.addEventListener(event, handler); // <-- Error
};
export default useEventListener;
用法类似于:
const exampleHandler = (event: MouseEvent) => console.log(event);
useEventListener("click", exampleHandler); // Correct
const exampleErroneusHandler = (event: KeyboardEvent) => console.log(event);
useEventListener("click", exampleErroneusHandler); // Error
上面的片段提供了以下错误:
类型‘(事件: EventsK) => void’的参数不能分配给'EventListenerOrEventListenerObject‘类型的参数。类型‘(事件: EventsK) => void’不能分配到键入'EventListener‘。参数'event‘和'evt’的类型是不兼容的。输入'EventsK‘不能分配’EventsK‘。输入“Event”不能键入'Event & ClipboardEvent & UIEvent & AnimationEvent & MouseEvent & InputEvent & FocusEvent & 21 more .& StorageEvent‘。属性“clipboardData”在“事件”类型中缺失,但在“剪贴板事件”类型中是必需的。(2345)
一个修复方法是使用一个不太特定的事件,而不是EventsK。
handler: (event: Event) => void,
是否有一种方法可以实现这一点而不求助于不太具体的事件类型?
(标题相当笨拙,可能会做得更好)
发布于 2022-05-24 20:45:36
基本上,您的类型检查有效,只需将处理程序转换为EventListener
即可。exampleErroneusHandler
处理KeyboardEvent
。而对类型的验证只允许MouseEvent
处理程序作为click
处理程序,而click
处理程序只能接受MouseEvent
处理程序。
我明白吗,您想要对EventMaps的密钥进行验证吗?作为你目前的设置,完全按照你的要求去做。我认为你应该把这个问题改为build a generic function which validates if the event name is allowed for a given event handler
。
这解决了你的问题
type Events = HTMLElementEventMap & WindowEventMap & DocumentEventMap;
type ListenerElements = HTMLElement | Window | Document;
function useEventListener<E extends Events[keyof Events]>(
event: keyof Pick<Events, {[K in keyof Events]: Events[K] extends E ? K : never}[keyof Events]>,
handler: (event: E) => void,
element: ListenerElements = window
) {
element.addEventListener(event, handler as EventListener);
};
const exampleHandler = (event: MouseEvent) => console.log(event);
useEventListener("click", exampleHandler); // Correct
const exampleErroneusHandler = (event: KeyboardEvent) => console.log(event);
useEventListener("click", exampleErroneusHandler); // Argument of type '"click"' is not assignable to parameter of type '"keydown" | "keypress" | "keyup"'.ts(2345)
使用以下资源TypeScript基本要素:条件过滤类型
https://stackoverflow.com/questions/72365139
复制相似问题