Rij*_*ijk 6 javascript addeventlistener typescript typescript-typings
我正在尝试在该addEventListener方法上编写一个抽象层,但遇到了打字问题。在下面的最小复制中;
function addEventListener<T extends EventTarget>(
element: T,
type: string,
handler: EventListener
) {
element.addEventListener(type, handler);
}
addEventListener<Window>(window, "mousedown", (event: MouseEvent) => {
console.log(event.pageX);
});
Run Code Online (Sandbox Code Playgroud)
TypeScript 抱怨参数类型与 MouseEvent 不兼容:
Argument of type '(event: MouseEvent) => void' is not assignable to parameter of type 'EventListener'.
Types of parameters 'event' and 'evt' are incompatible.
Type 'Event' is missing the following properties from type 'MouseEvent': altKey, button, buttons, clientX, and 20 more.
Run Code Online (Sandbox Code Playgroud)
我知道以下(基本)事件侦听器:
Argument of type '(event: MouseEvent) => void' is not assignable to parameter of type 'EventListener'.
Types of parameters 'event' and 'evt' are incompatible.
Type 'Event' is missing the following properties from type 'MouseEvent': altKey, button, buttons, clientX, and 20 more.
Run Code Online (Sandbox Code Playgroud)
工作得很好,所以我假设在将handler参数输入as 时出现问题EventListener,但我无法弄清楚它应该是什么..我遇到的大多数答案似乎特定于 React,这与我的情况无关。
上面的代码片段:TypeScript Playground | 代码沙盒
问题是,你的addEventListener()打字不知道该怎么办type参数涉及的亚型Event是handler应该接受的。在 TypeScript 标准库文件中lib.dom.d.ts,各个EventTarget类型被赋予了一个非常具体的从type到 的映射handler。例如,Window接口的addEventListener方法签名如下所示:
addEventListener<K extends keyof WindowEventMap>(
type: K,
listener: (this: Window, ev: WindowEventMap[K]) => any,
options?: boolean | AddEventListenerOptions
): void;
Run Code Online (Sandbox Code Playgroud)
其中WindowEventMap被这里定义为之间有大的映射type的名称和Event类型。mousedown具体来说,对于键,属性值类型是MouseEvent。因此当你打电话
window.addEventListener('mousedown', (event: MouseEvent) => {
console.log(event.pageX);
});
Run Code Online (Sandbox Code Playgroud)
一切正常,因为K推断为是"mousedown",因此handler参数需要 a MouseEvent。
如果没有那种映射信息,类型往往看起来像typeisstring和listeneris (event: Event)=>void。但是,正如您所见,您不能简单地将 a 传递(event: MouseEvent)=>void给期望 a 的参数(event: Event)=>void,因为这样做通常是不安全的。如果你给我一个只接受MouseEvents的函数,我就不能把它当作一个接受所有Events的函数。如果我尝试,并且您给我的函数访问类似pageX属性的内容,我可能会收到运行时错误。
这种对函数参数的限制是在 TypeScript 2.6 中作为--strictFunctionTypes编译器选项添加的。如果您关闭该编译器选项,您的错误应该会消失,但我不建议您这样做。
相反,如果您只想为您的addEventListener函数放宽类型,您可以在Event子类型中使其通用,如下所示:
function addEventListener<T extends EventTarget, E extends Event>(
element: T, type: string, handler: (this: T, evt: E) => void) {
element.addEventListener(type, handler as (evt: Event) => void);
}
Run Code Online (Sandbox Code Playgroud)
然后你的代码将编译:
addEventListener(window, "mousedown", (event: MouseEvent) => {
console.log(event.pageX);
});
Run Code Online (Sandbox Code Playgroud)
但请记住:这种打字太松,无法捕捉错误,例如:
addEventListener(document.createElement("div"), "oopsie",
(event: FocusNavigationEvent) => { console.log(event.originLeft); }
);
Run Code Online (Sandbox Code Playgroud)
如果你直接在 an 上尝试,HTMLDivElement你会得到一个错误:
document.createElement("div").addEventListener("oopsie",
(event: FocusNavigationEvent) => { console.log(event.originLeft); }
); // error! oopsie is not acceptable
Run Code Online (Sandbox Code Playgroud)
在您修复这两个type参数之前,这不会得到解决
document.createElement("div").addEventListener("blur",
(event: FocusNavigationEvent) => { console.log(event.originLeft); }
); // error! FocusNavigationEvent is not a FocusEvent
Run Code Online (Sandbox Code Playgroud)
并使用匹配的Event子类型
document.createElement("div").addEventListener("blur",
(event: FocusEvent) => { console.log(event.relatedTarget); }
); // okay now
Run Code Online (Sandbox Code Playgroud)
所以,这就是我所能做到的。您可以尝试将所有已知EventTarget类型映射到type每个目标的所有正确参数,然后映射到Event每个EventTarget/type对的所有正确子类型,并具有一个有效的通用addEventListener函数......但它可以在lib.dom.d.ts文件的大小,我不想在这上面花太多时间。如果您需要类型安全,最好不要使用这个特定的抽象。否则,如果您对编译器遗漏了一些不匹配的情况感到满意,那么上述类型可能是一种可行的方法。
好的,希望有帮助;祝你好运!
| 归档时间: |
|
| 查看次数: |
3128 次 |
| 最近记录: |