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<HTMLInputElement>, o TypeScript sabe que event.target e um input e te da acesso a .value, .checked, .name e todas as propriedades de input.
// 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
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} onChange={handleName} />
<input type="number" value={age} onChange={handleAge} />
<textarea value={bio} onChange={handleBio} />
<select value={role} onChange={handleRole}>
<option value="dev">Dev</option>
<option value="designer">Designer</option>
</select>
<input type="checkbox" checked={agreed} onChange={handleAgreed} />
</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 onContextMenu={handleContextMenu} onMouseEnter={handleMouseEnter}>
<button onClick={handleClick}>Clique 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 onSubmit={handleSubmit}>
<input name="email" type="email" onChange={handleChange} />
<input name="password" type="password" onChange={handleChange} />
<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 onKeyDown={handleKeyDown} 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 onClick={onClick} onMouseEnter={onHover}>
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
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.