React Event Handlers with TypeScript
In this post, we’ll cover how to implement React event handlers that have strongly-typed parameters with TypeScript.
React event types
The React event system is a wrapper around the browser’s native event system. TypeScript types for this event system are available in the @types/react
npm package. These types can be used to strongly-type event parameters. Some of the common ones are:
ChangeEvent<T>
KeyboardEvent<T>
MouseEvent<T>
FormEvent<T>
These types are all derived from SyntheticEvent<T>
.
All the event types are generic and take in the type for the element that raised the event. For example, MouseEvent<HTMLButtonElement>
could be used for the parameter type for a button click handler.
Inline event handlers
If the event handler is implemented inline in the JSX element, it is automatically strongly-typed. Consider the example below:
<input
type="text"
value={criteria}
onChange={(e) =>
setCriteria(e.currentTarget.value)
}
/>
TypeScript is able to infer the type of e
to be ChangeEvent<HTMLInputElement>
. So, we get nice autocompletion when we reference e
:
Named event handlers
The typing is a little more tricky when a named function is used for the event handler. Consider the example below:
function Searchbox() {
const [criteria, setCriteria] = React.useState(
""
);
const handleChange = (e) => { setCriteria(e.currentTarget.value); }; return (
<input
type="text"
value={criteria}
onChange={handleChange}
/>
);
}
TypeScript infers the type of the e
parameter in handleChange
to be any
. So, no type checking will occur when e
is referenced in the handler implementation.
Not good!
We can use a type annotation to define the type of e
explicitly. What type should e
be set to? Well, a neat tip is to hover over the event handler prop to find out:
So, the type is ChangeEvent<HTMLInputElement>
. So, a strongly-typed version of the handleChange
event handler is as follows:
const handleChange = (
e: React.ChangeEvent<HTMLInputElement>) => {
setCriteria(e.currentTarget.value);
};
Neat!
Cross element event handlers
What about event handlers that handle events from multiple elements? Consider the example below:
const handleChange = (fieldName: string) => (e) => { ...};
return (
...
<input
type="text"
placeholder="Enter your name"
value={values.name}
onChange={handleChange("name")} />
<textarea
placeholder="Enter some notes"
value={values.notes}
onChange={handleChange("notes")} />
...
);
The e
parameter in the event handler is of type any
at the moment.
We can use the ChangeEvent
type for e
, but what element type do we pass into this generic type? The event handler is handling events for two different elements - HTMLInputElement
and HTMLTextAreaElement
. We can use the union type, HTMLInputElement | HTMLTextAreaElement
, for these elements. So, a strongly-typed event handler is as follows:
const handleChange = (fieldName: string) => (
e: React.ChangeEvent< HTMLInputElement | HTMLTextAreaElement >) => {
...
};
We can also narrow down the type for the fieldName
if we have a type for all the field values. In this example the type of values
is:
type NameAndNotes = {
name: string;
notes: string;
};
So, we can improve the typing of fieldName
with the keyof
keyword as follows:
const handleChange = (fieldName: keyof NameAndNotes) => ( ... ) => ...
Neat!
Wrap up
Standard event types for React are available in @types/react
. This includes generic types that can be used to strongly-type event handler parameters by passing the type for element raising the event.
TypeScript can infer inline event handler parameter types. We need to explicitly use a type annotation for the parameter in a named event handler. We can hover over the event handler prop to discover what the handler parameter type should be.
Did you find this post useful?
Let me know by sharing it on Twitter.If you to learn more about using TypeScript with React, you may find my course useful: