Carl Rippon

Building SPAs

Carl Rippon
BlogBooks / CoursesAbout
This site uses cookies. Click here to find out more

React Event Handlers with TypeScript

October 14, 2020

In this post, we’ll cover how to implement React event handlers that have strongly-typed parameters with TypeScript.

Strongly-typed React Events

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:

  onChange={(e) =>

TypeScript is able to infer the type of e to be ChangeEvent<HTMLInputElement>. So, we get nice autocompletion when we reference e:

Inline handler autocomplete

🏃 Play with the code

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 (

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:

Hover tip

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>) => {


🏃 Play with the code

Cross element event handlers

What about event handlers that handle events from multiple elements? Consider the example below:

const handleChange = (fieldName: string) => (e) => {  ...};
return (
    placeholder="Enter your name"
    onChange={handleChange("name")}  />
    placeholder="Enter some 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) => ( ... ) => ...


🏃 Play with the code

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.
Click here to share this post on Twitter

If you to learn more about using TypeScript with React, you may find my course useful:

Using TypeScript with React

Using TypeScript with React
Find out more

Want more content like this?

Subscribe to receive notifications on new blog posts and courses

© Carl Rippon
Privacy Policy