Let us assume we want to log the ID attribute of a clicked element with the following TypeScript code:
onClick(event) {
console.log(event.target.attributes.id.nodeValue);
}
The above function receives the clicked object as a parameter, but the type in this case is any
. If I check the result of typeof event
I get object
. So I would modify my code as follows:
onClick(event: object) {
console.log(event.target.attributes.id.nodeValue);
}
In this case, I receive an error in VS Code as below:
So what is up with this? Using the type any
as parameter type works, the console logs the desired ID without any error, but if I decide to use a strict object
as parameter type, my code does not compile. Where is the issue?
The affected HTML code is the following;
<h1 id="foo" (click)="onClick($event)">...</h1>
CodePudding user response:
If I check the result of
typeof event
I getobject
.
That's runtime code, so it's the JavaScript typeof
operator, which says "object"
for all objects (and null
).
So I would modify my code as follows...I receive an error is VS Code like below
Plain objects don't have a target
property.
The type of the event object for a click
event is MouseEvent
. (You've tagged jquery and angular. If you're using jQuery or the DOM to attach the event, it'll be the DOM's MouseEvent
. If you're using Angular to attach the event, it looks like it'll also be the DOM's MouseEvent
. Caveat: I don't use Angular.) You'd also probably want event.currentTarget.id
or event.target.id
rather than using the attributes
collection and nodeValue
, since the id
attribute is a reflected property.
But, the DOM's MouseEvent
interface inherits its currentTarget
property from Event
, which just defines it as an EventTarget
. You know that it will be an Element
, but unfortunately the interface just says it's EventTarget
. (The same is true for target
.)
As far as I'm aware, there's no predefined interface for a MouseEvent
that defines currentTarget
as Element
instead. You can reliably (in this situation) use a type assertion:
onClick(event: MouseEvent) {
console.log((event.target as Element).id); // Or `(event.currentTarget as Element).id`
}
I don't like type assertions, but they are sometimes necessary.
Sometimes you see people doing that same assertion slightly differently, like this:
onClick({target}: {target: Element}) {
console.log(target.id);
}
// or
onClick({currentTarget}: {currentTarget: Element}) {
console.log(currentTarget.id);
}
You might create a reusable type instead, like this:
interface ElementMouseEvent extends MouseEvent {
currentTarget: Element;
target: Element;
}
...and then use it (which is still making an assertion, but again, a safe one):
onClick(event: ElementMouseEvent) {
console.log(event.target.id); // Or `event.currentTarget.id`
}