TypeScript Version: 3.2.4
Search Terms:
event.target instanceof HTMLElement eventTarget not instanceof HTMLElement
Code
// event.target is instanceof HTMLElement
document.querySelector("div").addEventListener("click", (event) => {
// shows error: "EventTarget is missing the following properties from HTMLElement ..."
let t: HTMLElement = event.target;
// Though:
console.log(event.target instanceof HTMLElement) //true
})
Expected behavior:
The interface EventTarget should extend HTMLElement or event.target should return HTMLElement
Actual behavior:
EventTarget is missing the following properties from HTMLElement ...
Playground Link:
https://www.typescriptlang.org/play/index.html#src=%2F%2FNot%20relevant%0D%0Alet%20div%20%3D%20document.createElement(%22div%22)%3B%0D%0Adiv.style.width%20%3D%20%22100px%22%3B%0D%0Adiv.style.height%20%3D%20%22100px%22%3B%0D%0Adiv.style.background%20%3D%20%22red%22%3B%0D%0Adocument.querySelector(%22body%22).append(div)%3B%0D%0A%0D%0A%2F%2Frelevant%0D%0Adocument.querySelector(%22div%22).addEventListener(%22click%22%2C%20(e)%20%3D%3E%20%7B%0D%0A%09let%20t%3A%20HTMLElement%20%3D%20e.target%3B%0D%0A%0D%0A%09console.log(e.target%20instanceof%20HTMLElement)%3B%0D%0A%7D)
Related Issues:
it's a limitation of the builtin types that not forwarding the generic type of the target.
A workaround would be:
if (event.target instanceof HTMLDivElement) {
....
}
The
currentTargetread-only property of theEventinterface identifies the current target for the event, as the event traverses the DOM. It always refers to the element to which the event handler has been attached, as opposed toEvent.target, which identifies the element on which the event occurred.
Consider clicking on the SVG element in the DOM structure below:
<div>
<svg />
</div>
document.querySelector("div").addEventListener("click", event => {
console.log(event.target instanceof HTMLElement) // false
});
The output is false.
You should almost always be using event.currentTarget.
You should almost always be using
event.currentTarget.
Even better, you should almost always be using this (if not within an arrow function):
my_element.addEventListener('click', function (e) {
console.log(this.className) // logs the className of my_element
console.log(e.currentTarget === this) // logs `true`
})
According to the DOM API, EventTarget does not extend HTMLElement — In fact, it is the other way around. HTMLElement extends Element, which extends Node, which extends EventTarget.
Even better, you should almost always be using
this(if not within an arrow function)
I would argue it is strictly worse to use this since (as you pointed out) the value of it can change depending on what function syntax you're using. Using the event.currentTarget will always be the same thing on which you called .addEventListener() regardless of function syntax.
@jcready true, but if there are no other references to the event param, then using this lets you get away with defining a parameter for the handler function. I guess it depends on preferred coding style.
In either case, event.currentTarget, specified as an EventTarget object, is not guaranteed to be an instance of HTMLElement, or even Element or Node for that matter. I’d vote to close this issue.
I use Visual Studio, not Code. Currently VS 2019.
A very common scenario to use event.target is event delegation, where you have a handler on the parent, and when a child is clicked you want to test tagName or classList of event.target. It works, I've done it for years, I just don't get intellisense on "tagName" and "classList" since target is not HTMLElement, but not a problem...would be nice if I did.
Most helpful comment
it's a limitation of the builtin types that not forwarding the generic type of the target.
A workaround would be: