import React, { useState, useRef } from 'react';
interface User {
id: number;
name: string;
}
export const UserForm = () => {
const [user, setUser] = useState<User | null>(null);
const [inputValue, setInputValue] = useState('');
const inputRef = useRef<HTMLInputElement>(null);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!inputValue) return;
setUser({ id: Date.now(), name: inputValue });
inputRef.current?.blur();
};
return (
<form onSubmit={handleSubmit}>
<input
ref={inputRef}
value={inputValue}
onChange={handleChange}
/>
<button type="submit">Salvează {user?.name}</button>
</form>
);
};Când am trecut prima oară un proiect de React pe TypeScript strict, prin 2018, am vrut să trag obloanele după primele zece minute. Ecranul era roșu de erori în terminal, iar tentația să pun any peste tot a fost uriașă. Dacă ești la primul proiect și te lupți cu compilatorul, hai să vedem cum rezolvi elegant cele mai frecvente erori.
Nu ești singurul care pățește asta, toți am trecut prin frustrarea de a scrie de trei ori mai mult cod doar pentru a mulțumi compilatorul.
1. Starea inițială e null la useState
Cea mai clasică eroare apare când vrei să aduci date dintr-un API. Scrii const [user, setUser] = useState(null), iar când încerci să accesezi user.name, TS explodează: Property 'name' does not exist on type 'null'.
TypeScript a dedus că starea ta va fi întotdeauna null fiindcă aceea a fost valoarea inițială. Rezolvarea stă în Generics. Trebuie să îi spui explicit compilatorului ce tip de date va conține acea stare în viitor.
// Definim tipul de date
interface UserProfile {
id: string;
name: string;
}
// Îi spunem lui useState că poate fi ori UserProfile, ori null
const [user, setUser] = useState<UserProfile | null>(null);
2. Event-urile din formulare (implicit any)
Scrii o funcție simplă de handleChange pentru un input. O muți în afara JSX-ului și imediat primești: Parameter 'e' implicitly has an 'any' type.
Când scrii funcția inline, TypeScript e destul de deștept să își dea seama de context. Când o muți separat, își pierde urma. Nu pune any la argumentul e. Folosește tipurile native puse la dispoziție de React.
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
};
Dacă ai un formular și asculți de onSubmit, tipul va fi React.FormEvent<HTMLFormElement>.
3. Unde a dispărut children în React 18?
La proiecte mai vechi, tipul React.FC (sau FunctionComponent) includea automat proprietatea children. De la React 18 încoace, echipa React a scos acest comportament implicit pentru că masca bug-uri unde componente care nu trebuiau să accepte copii primeau totuși elemente în interior.
Acum, dacă folosești children, trebuie să îl declari explicit în interfața de Props.
interface CardProps {
title: string;
children: React.ReactNode; // Tipul corect pentru orice poate fi randat în React
}
4. Eroarea de indexare (Element implicitly has an 'any' type)
Am pățit-o la un script de configurare pentru un dashboard cu vreo 12 setări diferite. Ai un obiect și vrei să accesezi o cheie dinamic, bazat pe o variabilă:
const themes = { dark: '#000', light: '#fff' };
let currentTheme = 'dark';
const color = themes[currentTheme]; // Eroare!
Pentru TS, currentTheme este un string oarecare, iar el nu poate garanta că acel string există ca cheie în obiectul themes. Soluția este să tipizezi variabila mai restrictiv, folosind keyof:
let currentTheme: keyof typeof themes = 'dark';
5. useRef și elementele de DOM
Când vrei să pui focus pe un input folosind un ref, scrii const inputRef = useRef(null). Când rulezi inputRef.current.focus(), TypeScript te avertizează că current este null sau că funcția focus nu există.
Trebuie să specifici ce tip de element HTML va stoca acel ref, iar la apelare să folosești un optional chaining (?.) pentru că valoarea de start este într-adevăr null până când se randează componenta.
const inputRef = useRef<HTMLInputElement>(null);
const handleClick = () => {
inputRef.current?.focus();
};
Trade-off-ul sincer
TypeScript strict îți va încetini viteza de dezvoltare cu aproximativ 20-30% la primul proiect. Te vei bate cu tipurile în loc să scrii logică de business. Totuși, la proiecte care trec de 5-6 luni de viață sau au peste 2 developeri, această investiție îți salvează nopțile pierdute căutând de ce un undefined a crăpat aplicația în producție.
Voi cum ați trecut peste faza de acomodare cu TypeScript? Ați fost tentați să lăsați setarea strict: false în tsconfig?