O terror silencioso de todo desenvolvedor React: event.target.value e TypeScript
Você já escreveu um manipulador onChange para um input simples, e o TypeScript de repente começou a gritar em vermelho? Familiar: "Property 'value' does not exist on type 'EventTarget'". Esta pergunta no Stack Overflow acumulou dezenas de milhares de visualizações, e não é à toa. Parece que poderia ser mais simples — pegar o valor do campo de entrada? Mas o diabo, como sempre, está nos detalhes.
Em 2025, o ecossistema TypeScript ficou ainda mais rigoroso. Novas versões do compilador analisam melhor os tipos, e os "hacks" antigos pararam de funcionar. Se você escreve em React ou simplesmente usa TypeScript para trabalhar com o DOM, este artigo é seu salva-vidas. Vamos analisar não apenas como tipificar onChange, mas também por que funciona dessa forma e não de outra. Vamos lá!
Por que event.target.value é um problema?
Vamos direto ao ponto. Aqui está um exemplo típico que causa erro:
const handleChange = (event: any) => { const value = event.target.value; // Funciona, mas "any" é o mal};O problema é que event pode ser qualquer coisa. O TypeScript não sabe qual elemento é e se ele tem a propriedade value. Além disso, usar any mata toda a magia da tipagem estática. Você perde o autocompletar e a proteção contra erros.
O caminho correto é usar tipos específicos. Mas quais? Vamos descobrir.
Melhores práticas para tipificar onChange em 2025
1. React: usando ChangeEvent
Se você trabalha com React, esqueça o Event nativo. O React usa seus próprios eventos sintéticos — SyntheticEvent. Para inputs, textareas e selects, o ideal é usar ChangeEvent.
import React, { ChangeEvent } from 'react';
const MyInput = () => { const handleChange = (event: ChangeEvent<HTMLInputElement>) => { const value = event.target.value; console.log(value); // value é string, TypeScript satisfeito };
return <input type="text" onChange={handleChange} />;};Por que isso funciona? ChangeEvent<HTMLInputElement> é um genérico que sabe exatamente que event.target é um HTMLInputElement. E ele tem a propriedade value do tipo string. Tudo lógico e type-safe.
2. Para textarea e select
Uma abordagem semelhante funciona para outros elementos de formulário. Basta alterar o genérico:
ChangeEvent<HTMLTextAreaElement>— para<textarea>ChangeEvent<HTMLSelectElement>— para<select>ChangeEvent<HTMLInputElement>— para<input>
const handleTextareaChange = (event: ChangeEvent<HTMLTextAreaElement>) => { const text = event.target.value; // string};
const handleSelectChange = (event: ChangeEvent<HTMLSelectElement>) => { const selectedValue = event.target.value; // string};3. TypeScript puro (sem React): Event + type assertion
Se você não usa React, mas trabalha diretamente com o DOM, é um pouco diferente. O Event nativo não conhece a propriedade value. Você precisa fazer um cast de event.target para o tipo correto.
const inputElement = document.getElementById('my-input') as HTMLInputElement;
inputElement.addEventListener('change', (event: Event) => { const target = event.target as HTMLInputElement; const value = target.value; console.log(value);});Importante: Use a type assertion (as HTMLInputElement) apenas quando tiver 100% de certeza sobre o tipo do elemento. Caso contrário, você corre o risco de obter um erro em tempo de execução.