Problem Solved

React + TS · event handlers

Home › Courses › TypeScript › Problems › Event handlers
🔷 Problem · 5 min read

How to type event handlers.
Every event, one cheat sheet.

React ships types for every DOM event — ChangeEvent, MouseEvent, FormEvent, KeyboardEvent, FocusEvent, and more. Each is a generic over the element type. Get the type right and e.target is properly typed with .value, .checked, .files, etc. Get it wrong and everything becomes any. This page is the complete reference.

Short answer: Use React.ChangeEvent for input changes, React.FormEvent for submits, React.MouseEvent for clicks, React.KeyboardEvent for key presses, React.FocusEvent for focus/blur. The element type is the element the handler attaches to. Inline handlers infer automatically — only named functions need annotations. Always prefer e.currentTarget over e.target for form/container events.

✅ Solution 1 — The event type cheat sheet

Every common event, mapped to its TypeScript type.

These are the types you'll reach for daily. Save this list — after a week, you'll recognize the pattern: React.[EventName]Event<[HTMLElement]>. The element generic is the type of the element you're attaching to.

cheatsheet.tsx
import { useState } from 'react';

function AllEvents() {
const [text, setText] = useState('');
const [checked, setChecked] = useState(false);
const [selected, setSelected] = useState('a');

// ─── Change — text input ─────────────────────
function onTextChange(e: React.ChangeEvent) {
setText(e.target.value); // string
}

// ─── Change — textarea ───────────────────────
function onTextareaChange(e: React.ChangeEvent) {
setText(e.target.value);
}

// ─── Change — select ────────────────��────────
function onSelectChange(e: React.ChangeEvent) {
setSelected(e.target.value);
}

// ─── Change — checkbox ───────────────────────
function onCheckChange(e: React.ChangeEvent) {
setChecked(e.target.checked); // boolean
}

// ─── Change — file input ─────────────────────
function onFileChange(e: React.ChangeEvent) {
const files = e.target.files; // FileList | null
if (files && files.length > 0) {
console.log(files[0].name);
}
}

// ─── Submit — form ───────────────────────────
function onSubmit(e: React.FormEvent) {
e.preventDefault();
const form = e.currentTarget;
console.log(new FormData(form));
}

// ─── Click — button ──────────────────────────
function onClick(e: React.MouseEvent) {
console.log('clicked at', e.clientX, e.clientY);
console.log('button disabled?', e.currentTarget.disabled);
}

// ─── Keyboard — input ────────────────────────
function onKeyDown(e: React.KeyboardEvent) {
if (e.key === 'Enter') console.log('submitted');
if (e.ctrlKey && e.key === 's') {
e.preventDefault();
console.log('saved');
}
}

// ─── Focus / Blur ────────────────────────────
function onFocus(e: React.FocusEvent) {
e.target.select();
}

// ─── The complete cheat sheet ────────────────
//
// onChange → React.ChangeEvent
// (or HTMLTextAreaElement, HTMLSelectElement)
// onSubmit → React.FormEvent
// onClick → React.MouseEvent
// (or HTMLDivElement, HTMLAnchorElement)
// onKeyDown → React.KeyboardEvent
// onKeyUp → React.KeyboardEvent
// onKeyPress → React.KeyboardEvent
// onFocus → React.FocusEvent
// onBlur → React.FocusEvent
// onScroll → React.UIEvent
// onMouseEnter → React.MouseEvent
// onMouseLeave → React.MouseEvent
// onDrag → React.DragEvent
// onDrop → React.DragEvent
// onWheel → React.WheelEvent
// onPointer → React.PointerEvent
// onTouch → React.TouchEvent
// onAnimation → React.AnimationEvent
// onTransition → React.TransitionEvent

return (