Forms and Events
If performance is not an issue (and it usually isn't!), inlining handlers is easiest as you can just use type inference and contextual typing:
const el = (
<button
onClick={(event) => {
/* event will be correctly typed automatically! */
}}
/>
);
But if you need to define your event handler separately, IDE tooling really comes in handy here, as the @type definitions come with a wealth of typing. Type what you are looking for and usually the autocomplete will help you out. Here is what it looks like for an onChange
for a form event:
type State = {
text: string;
};
class App extends React.Component<Props, State> {
state = {
text: "",
};
// typing on RIGHT hand side of =
onChange = (e: React.FormEvent<HTMLInputElement>): void => {
this.setState({ text: e.currentTarget.value });
};
render() {
return (
<div>
<input type="text" value={this.state.text} onChange={this.onChange} />
</div>
);
}
}
View in the TypeScript Playground
Instead of typing the arguments and return values with React.FormEvent<>
and void
, you may alternatively apply types to the event handler itself (contributed by @TomasHubelbauer):
// typing on LEFT hand side of =
onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
this.setState({text: e.currentTarget.value})
}
Why two ways to do the same thing?
The first method uses an inferred method signature (e: React.FormEvent<HTMLInputElement>): void
and the second method enforces a type of the delegate provided by @types/react
. So React.ChangeEventHandler<>
is simply a "blessed" typing by @types/react
, whereas you can think of the inferred method as more... artisanally hand-rolled. Either way it's a good pattern to know. See our Github PR for more.
Typing onSubmit, with Uncontrolled components in a Form
If you don't quite care about the type of the event, you can just use React.SyntheticEvent
. If your target form has custom named inputs that you'd like to access, you can use a type assertion:
<form
ref={formRef}
onSubmit={(e: React.SyntheticEvent) => {
e.preventDefault();
const target = e.target as typeof e.target & {
email: { value: string };
password: { value: string };
};
const email = target.email.value; // typechecks!
const password = target.password.value; // typechecks!
// etc...
}}
>
<div>
<label>
Email:
<input type="email" name="email" />
</label>
</div>
<div>
<label>
Password:
<input type="password" name="password" />
</label>
</div>
<div>
<input type="submit" value="Log in" />
</div>
</form>
View in the TypeScript Playground
Of course, if you're making any sort of significant form, you should use Formik or React Hook Form, which are written in TypeScript.
List of event types
Event Type | Description |
---|---|
AnimationEvent | CSS Animations. |
ChangeEvent | Changing the value of <input> , <select> and <textarea> element. |
ClipboardEvent | Using copy, paste and cut events. |
CompositionEvent | Events that occur due to the user indirectly entering text (e.g. depending on Browser and PC setup, a popup window may appear with additional characters if you e.g. want to type Japanese on a US Keyboard) |
DragEvent | Drag and drop interaction with a pointer device (e.g. mouse). |
FocusEvent | Event that occurs when elements gets or loses focus. |
FormEvent | Event that occurs whenever a form or form element gets/loses focus, a form element value is changed or the form is submitted. |
InvalidEvent | Fired when validity restrictions of an input fails (e.g <input type="number" max="10"> and someone would insert number 20). |
KeyboardEvent | User interaction with the keyboard. Each event describes a single key interaction. |
MouseEvent | Events that occur due to the user interacting with a pointing device (e.g. mouse) |
PointerEvent | Events that occur due to user interaction with a variety pointing of devices such as mouse, pen/stylus, a touchscreen and which also supports multi-touch. Unless you develop for older browsers (IE10 or Safari 12), pointer events are recommended. Extends UIEvent. |
TouchEvent | Events that occur due to the user interacting with a touch device. Extends UIEvent. |
TransitionEvent | CSS Transition. Not fully browser supported. Extends UIEvent |
UIEvent | Base Event for Mouse, Touch and Pointer events. |
WheelEvent | Scrolling on a mouse wheel or similar input device. (Note: wheel event should not be confused with the scroll event) |
SyntheticEvent | The base event for all above events. Should be used when unsure about event type |
What about InputEvent
?
You've probably noticed that there is no InputEvent
. This is because it is not supported by Typescript as the event itself has no fully browser support and may behave differently in different browsers. You can use KeyboardEvent
instead.
Sources: