L'horreur silencieuse de chaque développeur React : event.target.value et TypeScript
Avez-vous déjà écrit un gestionnaire onChange pour un simple champ de saisie, et TypeScript s'est soudainement mis à crier en rouge ? Cela vous dit quelque chose : "Property 'value' does not exist on type 'EventTarget'". Cette question sur Stack Overflow a recueilli des dizaines de milliers de vues, et ce n'est pas pour rien. Quoi de plus simple, semble-t-il, que de récupérer la valeur d'un champ de saisie ? Mais le diable, comme toujours, se cache dans les détails.
En 2025, l'écosystème TypeScript est devenu encore plus strict. Les nouvelles versions du compilateur analysent mieux les types, et les anciennes "astuces" ont cessé de fonctionner. Si vous développez avec React ou utilisez simplement TypeScript pour travailler avec le DOM, cet article est votre bouée de sauvetage. Nous allons décortiquer non seulement comment typer onChange, mais aussi pourquoi cela fonctionne de cette manière et pas d'une autre. C'est parti !
Pourquoi event.target.value est-il un problème ?
Allons droit au but. Voici un exemple typique qui provoque une erreur :
const handleChange = (event: any) => { const value = event.target.value; // Fonctionne, mais "any" est un mal};Le problème est que event peut être n'importe quoi. TypeScript ne sait pas de quel élément il s'agit ni s'il possède une propriété value. De plus, utiliser any tue toute la magie du typage statique. Vous perdez l'autocomplétion et la protection contre les erreurs.
La bonne approche consiste à utiliser des types spécifiques. Mais lesquels ? Voyons cela.
Meilleures pratiques pour typer onChange en 2025
1. React : utiliser ChangeEvent
Si vous travaillez avec React, oubliez l'événement natif Event. React utilise ses propres événements synthétiques — SyntheticEvent. Pour les champs de saisie, les zones de texte et les listes déroulantes, ChangeEvent est parfaitement adapté.
import React, { ChangeEvent } from 'react';
const MyInput = () => { const handleChange = (event: ChangeEvent<HTMLInputElement>) => { const value = event.target.value; console.log(value); // value est une chaîne, TypeScript est content };
return <input type="text" onChange={handleChange} />;};Pourquoi cela fonctionne-t-il ? ChangeEvent<HTMLInputElement> est un générique qui sait précisément que event.target est un HTMLInputElement. Et celui-ci possède une propriété value de type string. Tout est logique et type-safe.
2. Pour textarea et select
Une approche similaire fonctionne pour les autres éléments de formulaire. Il suffit de changer le générique :
ChangeEvent<HTMLTextAreaElement>— pour<textarea>ChangeEvent<HTMLSelectElement>— pour<select>ChangeEvent<HTMLInputElement>— pour<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 pur (sans React) : Event + assertion de type
Si vous n'utilisez pas React et travaillez directement avec le DOM, c'est un peu différent. L'événement natif Event ne connaît pas la propriété value. Vous devez convertir event.target vers le type correct.
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);});Important : Utilisez la conversion de type (as HTMLInputElement) uniquement lorsque vous êtes sûr à 100 % du type de l'élément. Sinon, vous risquez une erreur à l'exécution.