Tipar Eventos no React com TypeScript
Cansado de colocar 'any' nos event handlers? Aqui voce aprende a tipar onClick, onChange, onSubmit e todos os eventos do React com TypeScript de uma vez.
Por que isso é importante
Tipar Eventos no React com TypeScript. Cansado de colocar 'any' nos event handlers? Aqui voce aprende a tipar onClick, onChange, onSubmit e todos os eventos do React com TypeScript de uma vez.
Como funciona o sistema de eventos do React com TypeScript
O React nao usa eventos nativos do DOM direto. Ele envolve tudo em SyntheticEvent, um wrapper cross-browser que tem a mesma interface dos eventos nativos mas funciona de forma padronizada. O TypeScript tem tipos especificos pra cada variante: ChangeEvent, MouseEvent, FormEvent, KeyboardEvent, FocusEvent, DragEvent e por ai vai.
Cada tipo de evento aceita um generico que define qual elemento HTML disparou o evento. Isso e o pulo do gato: quando voce diz React.ChangeEvent
// Hierarquia de tipos de evento no React
SyntheticEvent // Base de todos
├── ChangeEvent // onChange
├── MouseEvent // onClick, onMouseEnter, etc.
├── FormEvent // onSubmit
├── KeyboardEvent // onKeyDown, onKeyUp, onKeyPress
├── FocusEvent // onFocus, onBlur
├── DragEvent // onDrag, onDrop
├── ClipboardEvent // onCopy, onPaste
├── TouchEvent // onTouchStart, onTouchEnd
├── WheelEvent // onWheel
└── AnimationEvent // onAnimationStart, onAnimationEnd
// Generico define o elemento HTML
React.ChangeEvent<HTMLInputElement>
React.MouseEvent<HTMLButtonElement>
React.FormEvent<HTMLFormElement>
Passo a passo: tipando eventos no React
- Identifique qual evento voce esta usando (onClick, onChange, onSubmit, etc.)
- Escolha o tipo React correto: MouseEvent, ChangeEvent, FormEvent, etc.
- Passe o elemento HTML como generico:
, - Use o tipo no parametro da funcao handler
- Acesse event.target com autocomplete completo e sem erros
- Para handlers passados como props, use React.EventHandler ou os tipos de handler especificos
Exemplos praticos de cada tipo de evento
ChangeEvent: inputs, selects e textareas
O evento mais usado no dia a dia. Cada tipo de input precisa do elemento HTML correto no generico. Olha a diferenca:
import React, { useState } from 'react';
function FormExample() {
const [name, setName] = useState('');
const [age, setAge] = useState(0);
const [bio, setBio] = useState('');
const [role, setRole] = useState('dev');
const [agreed, setAgreed] = useState(false);
// Input de texto
const handleName = (e: React.ChangeEvent<HTMLInputElement>) => {
setName(e.target.value); // .value e string
};
// Input numerico
const handleAge = (e: React.ChangeEvent<HTMLInputElement>) => {
setAge(Number(e.target.value));
};
// Textarea
const handleBio = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setBio(e.target.value);
};
// Select
const handleRole = (e: React.ChangeEvent<HTMLSelectElement>) => {
setRole(e.target.value);
};
// Checkbox
const handleAgreed = (e: React.ChangeEvent<HTMLInputElement>) => {
setAgreed(e.target.checked); // .checked e boolean
};
return (
<form>
<input type="text" value={name} />
<input type="number" value={age} />
<textarea value={bio} />
<select value={role}
<option value="dev">Dev</option>
<option value="designer">Designer</option>
</select>
<input type="checkbox" checked={agreed} />
</form>
);
}
MouseEvent: clicks e interacoes de mouse
MouseEvent te da acesso a coordenadas do clique, qual botao foi pressionado e se teclas modificadoras (Ctrl, Shift) estavam ativas. Super util pra menus contextuais e interacoes avancadas.
import React from 'react';
function InteractiveArea() {
// Click em botao
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
console.log('Coordenadas:', e.clientX, e.clientY);
console.log('Ctrl pressionado:', e.ctrlKey);
};
// Click em div (menu contextual)
const handleContextMenu = (e: React.MouseEvent<HTMLDivElement>) => {
e.preventDefault();
console.log('Menu em:', e.pageX, e.pageY);
};
// Mouse enter/leave
const handleMouseEnter = (e: React.MouseEvent<HTMLDivElement>) => {
const target = e.currentTarget; // tipo: HTMLDivElement
target.style.backgroundColor = '#333';
};
return (
<div
<button aqui</button>
</div>
);
}
FormEvent e onSubmit
O FormEvent e o que voce usa no onSubmit. O detalhe importante: use e.currentTarget ao inves de e.target pra acessar os campos do formulario de forma tipada.
import React, { useState } from 'react';
interface LoginData {
email: string;
password: string;
}
function LoginForm() {
const [formData, setFormData] = useState<LoginData>({
email: '',
password: '',
});
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// Tipo seguro: formData ja e LoginData
console.log('Login:', formData.email);
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
return (
<form
<input name="email" type="email" />
<input name="password" type="password" />
<button type="submit">Entrar</button>
</form>
);
}
KeyboardEvent: atalhos de teclado
import React from 'react';
function SearchInput() {
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
console.log('Buscando...');
}
if (e.key === 'Escape') {
(e.target as HTMLInputElement).blur();
}
// Atalho Ctrl+K
if (e.ctrlKey && e.key === 'k') {
e.preventDefault();
console.log('Atalho de busca');
}
};
return <input placeholder="Buscar..." />;
}
Event handlers como props
Quando voce precisa passar um handler como prop, existem dois jeitos de tipar. O React tem tipos de handler prontos que simplificam bastante:
// Jeito 1: tipo do handler completo
interface ButtonProps {
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
onHover?: (e: React.MouseEvent<HTMLButtonElement>) => void;
}
// Jeito 2: tipos de handler do React (mais limpo)
interface ButtonProps2 {
onClick: React.MouseEventHandler<HTMLButtonElement>;
onHover?: React.MouseEventHandler<HTMLButtonElement>;
}
// Jeito 3: generico pra qualquer evento
interface InputProps {
onChange: React.ChangeEventHandler<HTMLInputElement>;
onFocus: React.FocusEventHandler<HTMLInputElement>;
onKeyDown: React.KeyboardEventHandler<HTMLInputElement>;
}
function CustomButton({ onClick, onHover }: ButtonProps2) {
return (
<button
Clique
</button>
);
}
Erros comuns ao tipar eventos
Armadilhas que pegam todo mundo
Confundir event.target com event.currentTarget e o erro numero 1. O target e o elemento que disparou o evento (pode ser um filho), enquanto currentTarget e o elemento onde o handler esta anexado. Outro erro classico: usar eventos nativos do DOM (Event, MouseEvent) ao inves dos tipos do React (React.MouseEvent). Sao tipos diferentes e nao sao intercambiaveis.
// ERRADO: tipo nativo do DOM ao inves do React
const handleClick = (e: MouseEvent) => {};
// Deveria ser: React.MouseEvent<HTMLButtonElement>
// ERRADO: generico errado no ChangeEvent
const handleChange = (e: React.ChangeEvent<HTMLButtonElement>) => {
e.target.value; // Erro: HTMLButtonElement nao tem .value
};
// Deveria ser: React.ChangeEvent<HTMLInputElement>
// ERRADO: target vs currentTarget
const handleDiv = (e: React.MouseEvent<HTMLDivElement>) => {
e.target; // tipo: EventTarget (generico demais!)
e.currentTarget; // tipo: HTMLDivElement (correto!)
};
// CERTO: usar currentTarget quando precisa do elemento do handler
const handleDivCorreto = (e: React.MouseEvent<HTMLDivElement>) => {
const element = e.currentTarget; // HTMLDivElement
element.dataset.id; // funciona!
};
Checklist: eventos React tipados
Checklist Final
- Usa React.ChangeEvent, React.MouseEvent (nao os tipos nativos do DOM)
- Generico do evento corresponde ao elemento HTML correto
- currentTarget usado quando precisa acessar o elemento do handler
- Handlers como props usam React.EventHandler types
- FormEvent usado no onSubmit com preventDefault
- KeyboardEvent.key usado ao inves do depreciado keyCode
- Nenhum 'any' nos parametros de event handlers
- Checkbox usa e.target.checked, text usa e.target.value
Domine tipagem React no projeto real
Projeto completo com TypeScript
Tipar eventos e uma daquelas habilidades que voce usa todo dia no trabalho. No CrazyStack voce pratica isso construindo formularios reais, dashboards interativos e componentes reutilizaveis — tudo tipado de ponta a ponta com TypeScript, React e Node.js.