Typescript:区分 HTMLElement 和 SVGElement 的 addEventListener
Typescript: differentiating HTMLElement's and SVGElement's addEventListener
我正在编写一个 class,它可以接受 HTMLElement
或 SVGElement
,并且想使用具有相同功能的 addEventListener
函数进行绑定和事件两种类型的签名。
我在下面隔离了一个测试用例。
我的问题:是否可以在不使用 instanceof
的情况下获得 eventListener
event
参数的正确类型?
type HTMLorSVGElement = HTMLElement | SVGElement;
function test() {
const htmlEl = document.querySelector('div');
const svgEl = document.querySelector('svg');
const randomEl: HTMLorSVGElement | null = Math.random() > 0.5 ? htmlEl : svgEl;
function eventListener(event: MouseEvent) {
console.log(event.clientX);
}
/*
This usage produces the folowing error
Error:(12, 39) TS2345: Argument of type '(event: MouseEvent) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'.
Type '(event: MouseEvent) => void' is not assignable to 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.
*/
randomEl?.addEventListener('click', eventListener);
/*
This doesn't produce an error
*/
if (randomEl instanceof HTMLElement) {
randomEl.addEventListener('click', eventListener);
} else if (randomEl instanceof SVGElement) {
randomEl.addEventListener('click', eventListener);
}
}
发生这种情况是因为当我们将 strictFunctionTypes flag 设置为 true 时,TypeScript 编译器会感到困惑。将 strict 设置为 true 也会设置此标志。
如错误消息所述,编译器对是否可以将您的 eventListener 函数(MouseEvent -> void)分配给一种类型的 EventListener 感到困惑,尽管它完全能够处理不太复杂的场景中的语法.
有一个简单的解决方法可以使代码编译并工作:
randomEl?.addEventListener('click', eventListener as EventListener);
或者我们可以在 tsconfig.
中使用 "strictFunctionTypes": false
关闭麻烦的标志。
我已经更新了 my CodePen 所以它可以在 strict 设置为 true 的情况下工作,尽管我认为 CodePen 站点实际上不允许您设置 strict 标志。如果您在本地复制代码,它应该可以工作。
有一个 open issue on the TypeScript github 与此相关(我是从哪里得到答案的!)。
我正在编写一个 class,它可以接受 HTMLElement
或 SVGElement
,并且想使用具有相同功能的 addEventListener
函数进行绑定和事件两种类型的签名。
我在下面隔离了一个测试用例。
我的问题:是否可以在不使用 instanceof
的情况下获得 eventListener
event
参数的正确类型?
type HTMLorSVGElement = HTMLElement | SVGElement;
function test() {
const htmlEl = document.querySelector('div');
const svgEl = document.querySelector('svg');
const randomEl: HTMLorSVGElement | null = Math.random() > 0.5 ? htmlEl : svgEl;
function eventListener(event: MouseEvent) {
console.log(event.clientX);
}
/*
This usage produces the folowing error
Error:(12, 39) TS2345: Argument of type '(event: MouseEvent) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'.
Type '(event: MouseEvent) => void' is not assignable to 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.
*/
randomEl?.addEventListener('click', eventListener);
/*
This doesn't produce an error
*/
if (randomEl instanceof HTMLElement) {
randomEl.addEventListener('click', eventListener);
} else if (randomEl instanceof SVGElement) {
randomEl.addEventListener('click', eventListener);
}
}
发生这种情况是因为当我们将 strictFunctionTypes flag 设置为 true 时,TypeScript 编译器会感到困惑。将 strict 设置为 true 也会设置此标志。
如错误消息所述,编译器对是否可以将您的 eventListener 函数(MouseEvent -> void)分配给一种类型的 EventListener 感到困惑,尽管它完全能够处理不太复杂的场景中的语法.
有一个简单的解决方法可以使代码编译并工作:
randomEl?.addEventListener('click', eventListener as EventListener);
或者我们可以在 tsconfig.
中使用"strictFunctionTypes": false
关闭麻烦的标志。
我已经更新了 my CodePen 所以它可以在 strict 设置为 true 的情况下工作,尽管我认为 CodePen 站点实际上不允许您设置 strict 标志。如果您在本地复制代码,它应该可以工作。
有一个 open issue on the TypeScript github 与此相关(我是从哪里得到答案的!)。