import React, { useState, ChangeEvent } from 'react';
interface User {
id: number;
name: string;
}
export const UserProfile = () => {
// 1. Folosim generics pentru a permite null inițial
const [user, setUser] = useState<User | null>(null);
const [inputValue, setInputValue] = useState("");
// 2. Tipizăm corect evenimentul de schimbare
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};
return (
<div>
<input value={inputValue} onChange={handleInputChange} />
<p>User: {user?.name ?? 'Guest'}</p>
</div>
);
};Am trecut la TS acum vreo 6 ani, forțat de un proiect enterprise unde bug-urile de tip "undefined is not a function" ne mâncau cam 20% din sprint. La început, recunosc, am înjurat mult compilatorul pentru că mă încetinea și părea că stă în calea productivității mele. Dar după ce am livrat primul modul complex fără niciun crash în producție, m-am convins că nu mai există drum de întoarcere.
Dacă ești la primul proiect unde ai pus strict: true în tsconfig (și sper că ai făcut-o, altfel TS e doar un decor costisitor), te vei lovi de niște erori clasice. Nu ești tu de vină, e doar ecosistemul care are niște convenții specifice pe care trebuie să le înveți. Iată ce am observat că îi blochează pe cei mai mulți.
1. Blestemul lui "any" și lenea de moment
Cea mai mare greșeală pe care o poți face e să scapi de erori folosind any. Am văzut asta la un dashboard complex cu peste 40 de tabele; developeri cu experiență au pus any peste tot ca să termine task-ul repede. Rezultatul? Au pierdut 3 zile la refactoring când au realizat că datele din API nu mai match-uiau cu UI-ul și TS nu i-a avertizat deloc.
Trade-off: Pierzi 2 minute acum să scrii un interface corect, dar economisești ore de debugging mai târziu. Dacă chiar nu știi ce primești de la un endpoint, folosește unknown, e mult mai sigur pentru că te obligă la type checking înainte să accesezi proprietăți.
2. Evenimentele din input-uri (onChange)
Eroarea aia lungă și roșie când încerci să pui un handler pe un onChange este probabil cel mai comun punct de frustrare. TS se plânge că e.target nu are proprietatea value pe care o cauți tu, pentru că, implicit, Event este mult prea generic. Soluția este să folosești tipurile dedicate din React. Da, e mult de scris, dar măcar ai autocomplete pe tot ce înseamnă eveniment și elemente HTML.
3. useState și inferența greșită
Dacă scrii const [user, setUser] = useState(null), TypeScript va infera că user este mereu null. Când încerci ulterior să faci setUser({ name: 'Eduard' }), compilatorul va urla. Am pățit asta de zeci de ori la început. Trebuie să fii explicit folosind generics. E o chestie mică, dar ignorarea ei duce la zeci de erori de tip "Property does not exist on type 'null'".
4. Props cu "children" în React 18
Dacă ai învățat React acum câțiva ani, știai că FC (FunctionComponent) includea automat children. Ei bine, în React 18 s-a scos asta pentru a fi mai expliciți. Acum trebuie să declari manual children: React.ReactNode în interfața props-urilor. Am avut cazul unui upgrade la un proiect cu 150 de componente unde am fost nevoit să adaug manual tipul pentru children peste tot. A fost o lecție dură despre de ce e bine să nu te bazezi pe tipuri implicite care se pot schimba la un update de librărie.
5. Type Assertion (operatorul "as")
E tentant să scrii const data = result as MyType. Pare că ai rezolvat problema, dar de fapt doar ai mințit compilatorul. Am avut un proiect unde un coleg a forțat un obiect din API să pară valid, deși lipseau câmpuri esențiale. Aplicația a crăpat în producție fix în locul unde TypeScript zicea că totul e ok. Folosește as doar când ești 100% sigur (de exemplu, la un element din DOM selectat manual) și preferă mereu validarea la runtime (cum e Zod) dacă datele vin din exterior.
TypeScript nu e despre a scrie cod mai repede, ci despre a dormi mai liniștit noaptea. Voi ce eroare de TS ați urât cel mai mult când ați început?