How to fix property not existing on EventTarget in TypeScript
A common error that occurs when working with the DOM in TypeScript
is “property ‘property name’ not existing on EventTarget”. This error occurs
when you try to access a property on an event target in TypeScript.
Property 'value' does not exist on type 'EventTarget'.Here’s an example of a code snippet that triggers this error:
function handleClick(event: Event) {
const { target } = event
console.log(target.value);
}
const button = document.querySelector('button');
if (button) {
button.addEventListener('click', handleClick);
}Inspect this code on the TypeScript Playground
If you compile the above snippet, the compiler will emit two errors:
targetis possiblynull.- Property
valuedoes not exist on typeEventTarget.
The first error occurs because the type of the target object is EventTarget | null and we’re trying to access a property on a nullable type which is not
allowed in TypeScript (if strictNullChecks is enabled). We can fix this error
by narrowing the type to just EventTarget through a type guard:
function handleClick(event: Event) {
const { target } = event
if (target) console.log(target.value);
}The second error occurs because the type of the target object is now
EventTarget, and this type only has three methods: addEventListener(),
removeEventListener(), and dispatchEvent(). When you try to access any other
property on the target object, it will throw an error because the property
will not be recognised in the EventTarget type.
VS Code provides autocompletion for valid properties on EventTarget
But we know that the target element is a button in this case so we need to
communicate that information to TypeScript so that it can allow us access
properties that are valid for HTMLButtonElement which is the appropriate type
for button elements in TypeScript.
The EventTarget type does not inherit from HTMLElement by default because
HTML elements are not the only things that can be event targets.
It’s left to you to determine what the proper type of the target object is
before TypeScript can allow you to access any properties not found on
EventTarget.
One way to fix this error is to type cast the target object with the as
keyword.
function handleClick(event: Event) {
const { target } = event
if (target) console.log((target as HTMLButtonElement).value);
}Or you can cast the type of event.target to HTMLButtonElement when creating
the target variable:
function handleClick(event: Event) {
const target = event.target as HTMLButtonElement;
if (target) console.log(target.value);
}Either way, the code compiles because you’ve asked the compiler to treat the
target object as an HTMLButtonElement so it allows you access the value
property since it exists on the type.
Another way is to define the type of the target object in the callback
function using the & type intersection operator:
function handleClick(event: Event & {
target: HTMLButtonElement
}) {
const { target } = event
console.log(target.value);
}This means we don’t need to use the type guard because the type of target does
not include null, and the types of the other properties on the event object
are left unchanged.
If you need to do this often, you can abstract this pattern into its own type by
extending the HTMLElement type with generics:
type HTMLElementEvent<T extends HTMLElement> = Event & {
target: T;
}
function handleClick(event: HTMLElementEvent<HTMLButtonElement>) {
const { target } = event
console.log(target.value);
}Now, if you need to access an event target in a different context, all you need
to do is replace the HTMLButtonElement type with the appropriate type for the
element.
Thanks for reading, and happy coding!