import React, { useState, useRef, ChangeEvent } from 'react';
interface UserFormProps {
initialName?: string;
onSave?: (name: string) => void;
}
export const UserForm = ({ initialName = '', onSave }: UserFormProps) => {
const [name, setName] = useState<string>(initialName);
const inputRef = useRef<HTMLInputElement>(null);
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setName(e.target.value);
};
const handleSubmit = () => {
if (name.trim()) {
onSave?.(name);
inputRef.current?.focus();
}
};
return (
<div>
<input ref={inputRef} value={name} onChange={handleChange} />
<button onClick={handleSubmit}>Salvează</button>
</div>
);
};Când am trecut prima dată o aplicație React de 12.000 de linii la strict: true în tsconfig.json, terminalul meu s-a umplut instant de 140 de erori. Majoritatea nu erau bug-uri reale, ci doar modul în care TypeScript ne obligă să fim exacți cu componentele și evenimentele noastre. Dacă ești la primul proiect de React cu TypeScript strict, uite cele 5 erori peste care dai sigur și cum să le rezolvi curat, fără să pui any peste tot.
1. Implicit 'any' la Props și children
Proiectele noi generate cu Vite sau Next.js vin cu modul strict deja activat. Scrii o componentă simplă wrapper și pac, primești red squiggly lines sub parametru sau pe children.
TypeScript nu mai ghicește tipurile automat. În loc să folosești vechiul React.FC (care aducea children implicit și crea unele probleme la tipare mai complexe), definește o interfață explicită. Pentru tot ce înseamnă conținut ce poate fi randat în JSX, folosește React.ReactNode.
2. e.target.value nu există pe EventTarget
Scrii un handler clasic de onChange și încerci să citești e.target.value. TypeScript se plânge imediat că EventTarget este mult prea generic și nu are proprietatea value.
Soluția este să tipezi parametrul e folosind tipul generat de React: React.ChangeEvent<HTMLInputElement>. În felul acesta, TS știe exact ce proprietăți are target-ul tău și primești și autocomplete curat în IDE. Evită să faci cast-uri forced cu as HTMLInputElement în corp – e mai curat să tipezi parametrul.
3. Nu poți accesa .current din useRef fără null check
Creezi un ref pentru un input cu const inputRef = useRef<HTMLInputElement>(null) și apoi apelezi inputRef.current.focus(). TypeScript îți aruncă eroarea Object is possibly 'null'.
E o protecție foarte utilă. La prima randare, elementul din DOM nu există încă, deci .current chiar este null. Soluția rapidă este să folosești optional chaining: inputRef.current?.focus(). TS este fericit, iar tu previi un crash în runtime dacă apelul are loc înainte ca componenta să fie montată.
4. State-ul care își schimbă tipul pe parcurs
Scrii const [user, setUser] = useState(null) și mai târziu, după un fetch, încerci să faci setUser({ name: 'Alex' }). TypeScript urlă pentru că a dedus că user poate fi doar null și nimic altceva.
Când lucrezi cu date asincrone sau opționale, trebuie să declari explicit tipul când apelezi hook-ul: useState<User | null>(null). Există un mic trade-off aici: scrii un pic mai mult cod boilerplate la început, dar scapi de zeci de bug-uri mai târziu când încerci să accesezi user.name fără să verifici dacă datele au fost încărcate.
5. Apelarea funcțiilor opționale primite în Props
Ai un prop opțional în interfață, cum ar fi onSelect?: (id: string) => void. Dacă încerci să-l apelezi direct cu onSelect(id), compilerul îți spune că obiectul este possibly undefined.
O opțiune veche era să pui un if (onSelect) { onSelect(id); }, dar syntax-ul modern te lasă să folosești optional call: onSelect?.(id). Codul rămâne scurt și ușor de citit.
La noi în echipă, după ce am eliminat complet any-urile și am reparat tipările la event-uri, am redus erorile de runtime de tip cannot read property of undefined cu aproape 80% în producție. Tu ce eroare de TypeScript te-a enervat cel mai mult când ai trecut la modul strict?