- React events and TypeScript: a complete guide
- Our toy example
- Adding in TypeScript
- Typing the event
- Typing the event handler
- Relying on inferred types
- Other React events
- Form Events
- Keyboard Events
- Wrap up
- Did you enjoy this article?
- You might also like
- React & TypeScript: use generics to improve your types
- React & TypeScript: how to type hooks (a complete guide)
- What are dependency arrays in React?
- How to set an interval in React (with examples)
- How to set a timeout in React (with examples)
- How to use React Context like a pro
- How to use React useReducer hook like a pro
- How to add keyboard shortcuts to your React app
- How to handle window.event with typescript ?
- How to make it in Typescript ?
- Be Aware !!
- By Shabazz
React events and TypeScript: a complete guide
Events are everywhere in React, but learning how to properly use them and their handlers with TypeScript can be surprisingly tricky. There are several ways to do it, some better than others.
In this article we’ll cover all kinds of events in TypeScript: click, form, select, input, . First we’ll see how to type events on a toy example, then I’ll show you how to type any event.
If you just want to quickly jump to the solution, use this link.
Our toy example
To show how to type events in React, we’ll use the following example:
import useState > from 'react'; export default function App() const [inputValue, setInputValue] = useState(''); const handleInputChange = (event) => setInputValue(event.target.value); >; const handleClick = (event) => console.log('Submit button clicked!'); >; return ( div className="App"> h1>Hello Worldh1> input value=inputValue> onChange=handleInputChange> /> button onClick=handleClick>>Submitbutton> div> ); >
It’s a very simple React app with an input field and a submit button. But if you’re using TypeScript with this code, it must be screaming all kinds of obscenities right now! Don’t worry, we’re about to see how to set it at ease.
Note that we don’t really use handleClick ‘s’ argument in this code, so you could just omit it and TypeScript would be happy. But I’ve included it anyway just to show how you would type if you’d had a use for it.
Don’t worry if you’d like to know about other events than those two. This code will be used as an example, then we’ll see how to type any event afterwards.
Adding in TypeScript
There are several ways to type the above code, and we’ll see the 3 main ones. There are:
- Typing the event handler argument
- Typing the event handler itself
- Relying on inferred types
Typing the event
Let’s start with typing the onClick event. This one is quite straightforward. React provides a MouseEvent type you can directly use!
import useState, MouseEvent > from 'react'; export default function App() const [inputValue, setInputValue] = useState(''); const handleInputChange = (event) => setInputValue(event.target.value); >; const handleClick = (event: MouseEvent) => console.log('Submit button clicked!'); >; return ( div className="App"> h1>Hello Worldh1> input value=inputValue> onChange=handleInputChange> /> button onClick=handleClick>>Submitbutton> div> ); >
The onClick event is actually generated by React itself: it’s a synthetic event. A synthetic event is a React wrapper around the native browser event, to always have the same API regardless of differences in browsers.
Let’s move on to the handleInputChange function.
It’s pretty similar to handleClick , with a significant difference. You also import a type directly from react, which this time is called ChangeEvent . The difference is that ChangeEvent is a Generic type to which you have to provide what kind of DOM element is being used.
Not sure what Generics are? Here is TypeScript’s guide to them. You can think about it as a type function that accepts one or more arguments, to enable the user of the generic to customize the exact type.
The result is the following:
import useState, ChangeEvent, MouseEvent > from 'react'; export default function App() const [inputValue, setInputValue] = useState(''); // the type variable must match the DOM element emitting the // event, an `input` in this case const handleInputChange = (event: ChangeEventHTMLInputElement>) => setInputValue(event.target.value); >; const handleClick = (event: MouseEvent) => console.log('Submit button clicked!'); >; return ( div className="App"> h1>Hello Worldh1> input value=inputValue> onChange=handleInputChange> /> button onClick=handleClick>>Submitbutton> div> ); >
One thing to note in the code above is that HTMLInputElement refers specifically to HTML’s input tag. If we were using a textarea , we would be using HTMLTextAreaElement instead.
And there you have it! You made TypeScript happy 😁
Note that MouseEvent is also a Generic type, so you can restrict it if necessary. For example, let’s restrict the above MouseEvent to specifically be a mouse event emanating from a button.
const handleClick = (event: MouseEventHTMLButtonElement>) => console.log('Submit button clicked!'); >;
Typing the event handler
Instead of typing the event itself, as we did above, we can also type the functions themselves.
It looks very similar, and it’s mostly a matter of taste. I find typing the event more flexible so I tend to use the first one, but being aware of this other option is always good.
import useState, ChangeEventHandler, MouseEventHandler > from 'react'; export default function App() const [inputValue, setInputValue] = useState(''); // the type variable must match the DOM element emitting the // event, an `input` in this case const handleInputChange: ChangeEventHandlerHTMLInputElement> = (event) => setInputValue(event.target.value); >; const handleClick: MouseEventHandler = (event) => console.log('Submit button clicked!'); >; return ( div className="App"> h1>Hello Worldh1> input value=inputValue> onChange=handleInputChange> /> button onClick=handleClick>>Submitbutton> div> ); >
Relying on inferred types
Lastly, you can also rely on inferred types and not type anything yourself. For this, you need to inline your callbacks, which isn’t always what you want to do.
import useState > from 'react'; export default function App() const [inputValue, setInputValue] = useState(''); return ( div className="App"> h1>Hello Worldh1> input value=inputValue> onChange=(event) => setInputValue(event.target.value)> /> button onClick=(event) => console.log('Submit button clicked!')>> Submit button> div> ); >
Other React events
Of course, there’s a lot of other events than the two shown above.
A good way to find the complete list supported by React is to have a peak at the type definitions, in the React typings source code itself!
You can notice that every event inherits from SyntheticEvent , which is the base event.
Form Events
Building forms is very common in web development. We already saw how to handle text inputs, let’s now see an example (directly taken from React’s docs on forms) of a select , as well as a form submit events.
import useState, ChangeEvent, FormEvent > from 'react'; export default function App() const [selectValue, setSelectValue] = useState('coconut'); const handleSubmit = (event: FormEvent) => console.log('Form was submitted!'); >; const handleChange = (event: ChangeEventHTMLSelectElement>) => setSelectValue(event.target.value); >; return ( div className="App"> h1>Hello Worldh1> form onSubmit=handleSubmit>> label> Pick your favorite flavor: select value=selectValue> onChange=handleChange>> option value="grapefruit">Grapefruitoption> option value="lime">Limeoption> option value="coconut">Coconutoption> option value="mango">Mangooption> select> label> input type="submit" value="Submit" /> form> div> ); >
As you can see, it looks very similar to our first example.
Keyboard Events
Lastly, let’s see an example of handling keyboard events since those are also quite common!
Want to learn how to implement a fully functioning keyboard shortcut in your app? Check out this article!
import useState, useEffect > from 'react'; export default function App() const [key, setKey] = useState(''); useEffect(() => // handle what happens on key press const handleKeyPress = (event: KeyboardEvent) => setKey(event.key); >; // attach the event listener document.addEventListener('keydown', handleKeyPress); // remove the event listener return () => document.removeEventListener('keydown', handleKeyPress); >; >, [handleKeyPress]); return ( div className="App"> h2>Try typing on a keyh2> p>Key typed: key>p> div> ); >
Wrap up
I hope this article clears up how to handle events with React and Typescript! As you can see, it’s pretty simple once you know how to do it.
Package versions at the time of writing
Did you enjoy this article?
If so, a quick share on Twitter could really help out!
You might also like
React & TypeScript: use generics to improve your types
React & TypeScript: how to type hooks (a complete guide)
What are dependency arrays in React?
How to set an interval in React (with examples)
How to set a timeout in React (with examples)
How to use React Context like a pro
How to use React useReducer hook like a pro
How to add keyboard shortcuts to your React app
Tutorials on React and Javascript, updated weekly!
© Copyright 2020- 2023 , Devtrium
How to handle window.event with typescript ?
Normally when we want to catch an event on a page in js:
window.onkeydown = function (event) < //Do something here >
How to make it in Typescript ?
window is defined will all events in lib.d.ts and this particular listener as:
addEventListener(type: "keydown", listener: (ev: KeyboardEvent) => any, useCapture?: boolean): void;
Also, in Typescript, we can handle it like this:
const controlDown = (event: KeyboardEvent) => < console.log(event); >; window.addEventListener('keydown', controlDown);
or this, if we want to keep our original “style” :
window.onkeydown = (ev: KeyboardEvent): any => < //do something >
Be Aware !!
Even when TypeScript is playing by JavaScript rules, however, there are limits to what the compiler will allow. Let’s try adjusting onClick to expect a number:
const onClick = (n: number) => < /* . */ >window.addEventListener('click', onClick);
This time, we’ll see the expected compiler error:
// Argument of type '(e: number) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'. // Type '(e: number) => void' is not assignable to type 'EventListenerObject'. // Property 'handleEvent' is missing in type '(e: number) => void'.
As one would expect, ‘click” or ‘ keydown» will spawn a Mousevent or KeyboardEvent – not a number.
So the right way to write the function onClick would be :
const onClick = (e: MouseEvent) => console.log(`($, $)`);
By Shabazz
Software Engineer, MCSD, Web developer & Angular specialist