Typing Event Handlers
On this page
Boundary Rule
- Type the event at the UI boundary, then convert it to domain primitives.
- Do not pass event objects to business logic or async code.
- Prefer onChange signatures like (value) instead of (event).
Common Event Types
- React.ChangeEvent for inputs and selects.
- React.MouseEvent for clicks.
- React.FormEvent for form submit.
Example: Extract Primitive Value
function SearchBox({ value, onValue }) {
function onChange(e: React.ChangeEvent<HTMLInputElement>) {
onValue(e.target.value);
}
return <input value={value} onChange={onChange} />;
}
Example: Submit Handler
function Form({ onSave }) {
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
await onSave();
}
return (
<form onSubmit={onSubmit}>
<button>Save</button>
</form>
);
}
Mixed Element Pitfall
- A generic handler typed for one element can break when reused for another element.
- Use separate handlers or type a union only when logic is truly shared.
Failure Modes
- Passing event objects into async functions and using them later.
- Incorrect event type causing unsafe casts.
- Stale closures reading old state inside handlers.
- Handlers doing heavy work on the main thread.
Production Checklist
- Handlers translate DOM events into domain intent quickly.
- Only primitives cross component boundaries.
- Submit handlers have in flight guards.
- High frequency handlers are debounced or throttled.