Let's say I have the following event handler (in React):
onClick={(e: MouseEvent<HTMLElement>) => {
const link = e.target.href;
I understand why TypeScript complains about the above code: e.target
could be an <a>
tag (in which case it will have an href
), or it could be some other element that doesn't have an href
, and things could break if it doesn't.
But when I use the optional chaining operator, it shouldn't matter whether e.target
has an href
or not:
onClick={(e: MouseEvent<HTMLElement>) => {
const link = e.target?.href;
And the same is true of this (more verbose) version:
onClick={(e: MouseEvent<HTMLElement>) => {
if (!e.target.href) return;
const link = e.target.href;
But no matter what, TypeScript gives me Property 'href' does not exist on type 'EventTarget'.ts(2339)
error.
How can I express "I don't care whether e.target
has an href
or not" (without using @ts-ignore
)?
Typescript complains because the HTMLElement
interface doesn't have the href
attribute. This is because this interface represents all the possible DOM elements, so it has their common properties.
You should use HTMLAnchorElement
instead.
If you cant define e: MouseEvent<HTMLAnchorElement>
, you can cast later in the function using const target = e.target as HTMLAnchorElement
.
Note that this approach is safe only if you are sure that e.target
is an HTMLAnchorElement
.
If you are treating generic HTMLElement
s, you can use a type guard:
const target = e.target
if ("href" in target) {
// here you can use `target.href`
}
Or, if you want a dedicated function
const isAnchorElem = (target): target is HTMLAnchorElement => "href" in target
const target = e.target
if (isAnchorElem(target)) {
// here `target` will be of type `HTMLAnchorElement`
}