To type React events and form handlers, use the event types from @types/react, such as ChangeEvent for inputs and FormEvent for forms. Inline handlers infer the event type automatically, so you only annotate when you extract a function into a separate declaration. The annotations are small and follow one predictable pattern, so they are easy to remember.
Let inference do the work
Install @types/react and @types/react-dom as dev dependencies, and use the .tsx extension for any file that contains JSX. Inline handlers then need no annotation, because the prop tells TypeScript which event it is.
import { useState } from "react";
function NameField() {
const [name, setName] = useState("");
return <input value={name} onChange={(e) => setName(e.target.value)} />;
}The onChange prop types e as the change event for an input, so e.target.value type-checks without any work. Most small components never need an explicit event type.
Type an extracted handler
When the handler moves into its own function, the event no longer has a prop to infer from. Annotate it with React.ChangeEvent and the element type.
function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
setName(event.currentTarget.value);
}The generic names the element the event fires on, so TypeScript knows the handler is for a text input. The same pattern covers textarea, select, and other editable elements.
Common event types
Four types cover most handlers.
- ChangeEvent for input and select edits.
- FormEvent for form submission.
- MouseEvent for clicks.
- KeyboardEvent for key presses.
Each takes the element as a type argument, as shown in the examples above. Every one extends React.SyntheticEvent, the shared base type. You can import them directly with import type { ChangeEvent } from "react", which reads shorter in files that use many types, and the full set lives in the @types/react definitions.
Read currentTarget for the typed element
event.currentTarget is typed as the element the handler is attached to, while event.target is a generic EventTarget. Reading currentTarget gives you the value without a cast.
function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
setName(event.currentTarget.value);
}In most React handlers currentTarget is exactly the element you want. A change handler shared by several fields can read currentTarget to get the field's value and its name attribute to tell the fields apart. Reserve target for cases where the event bubbles from a child and you need the original source.
Type a form submit handler
A form's onSubmit receives FormEvent with the form element type. preventDefault and FormData both work on currentTarget.
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
const data = new FormData(event.currentTarget);
const email = data.get("email");
}The handler stops the reload and reads named fields from the submitted form. The generic ties the event to HTMLFormElement, so currentTarget is a form with all its methods.
What to learn next
The same typing ideas extend to typing component props and the events overview, which covers the runtime side of these handlers.
Rune AI
Key Insights
⚠ This article has a formatting issue and may not display correctly.
Our team has been notified. The content is shown as plain text below.
Frequently Asked Questions
Do I need to type inline event handlers?
Why use currentTarget instead of target?
What type do I use for a form submit handler?
Conclusion
⚠ This article has a formatting issue and may not display correctly.
Our team has been notified. The content is shown as plain text below.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.