"Property 'value' does not exist on type 'EventTarget'" — how to stop fearing and start typing events in TypeScript
\n\nHave you ever written an event handler in TypeScript, tried to get event.target.value — and immediately got a red underline and the message: "Property 'value' does not exist on type 'EventTarget'"? If so — you are not alone. On Stack Overflow, this question has gathered tens of thousands of views, and it continues to plague beginners and experienced developers in 2025.
The problem is not that TypeScript is "evil" or "broken." Quite the opposite: the compiler protects you from silly errors that could crash at runtime. Let's figure out why this error occurs and how to fix it properly.
\n\nWhy does TypeScript complain about event.target.value?
\n\nThe short answer: event.target has the type EventTarget | null. And EventTarget does not have a value property. It only has three methods: addEventListener, removeEventListener, and dispatchEvent.
When you write:
\n\nconst handleChange = (event: React.ChangeEvent) => {\n const value = event.target.value; // ❌ Error!\n};\n\n\nTypeScript sees: "Hey, I don't know which specific HTML element triggered this event. It could be a <div>, which has no value, or it could be an <input> — I'm not sure. So I refuse to compile this code."
This is a feature, not a bug. TypeScript forces you to explicitly specify which element you are working with.
\n\nTop 3 solutions (relevant for 2025)
\n\nThere are several approaches. We'll look at the most popular and safest ones.
\n\n1. Cast with as HTMLInputElement (fast, but cautious)
\n\nThe most common way is to cast event.target to the required type:
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n const value = (event.target as HTMLInputElement).value;\n console.log(value);\n};\n\n\nPros: simple, clear, works.
\nCons: if you are mistaken and the event actually came from a <textarea> or <select>, you will get undefined at runtime. The compiler will not warn you.
It's better to use this method when you are absolutely sure about the element type. For example, in simple forms with a single field.
\n\n2. Use event.currentTarget instead of event.target
\n\nIn TypeScript, currentTarget is typed more strictly than target. If you specify a generic parameter for the event, then currentTarget will have the correct type:
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n const value = event.currentTarget.value; // ✅ Works without a cast!\n};\n\n\nImportant: currentTarget is the element to which the handler is attached. If you attached the handler to an <input>, then currentTarget will always be that <input>. Unlike target, which could be a nested element (e.g., a <span> inside a button).
Pros: safer than a cast, no need to write extra type assertions.
\nCons: not suitable for all scenarios — for example, with bubbling events, currentTarget may not match the target element.
3. Generic function with type checking (the safest way)
\n\nIf you want maximum safety and reusability, write a helper function that checks the element type:
\n\nfunction getInputValue(event: Event): string