import { useState, useRef, type ChangeEvent, type FormEvent, type ReactNode } from 'react';
type CardProps = {
title: string;
children: ReactNode;
onSave?: (value: string) => void;
};
export const UserCard = ({ title, children, onSave }: CardProps) => {
const [text, setText] = useState<string>('');
const inputRef = useRef<HTMLInputElement>(null);
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setText(e.target.value);
};
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
onSave?.(text);
inputRef.current?.focus();
};
return (
<form onSubmit={handleSubmit}>
<h3>{title}</h3>
{children}
<input ref={inputRef} value={text} onChange={handleChange} />
<button type="submit">Salvează</button>
</form>
);
};Când am trecut prima oară un proiect de React de vreo 12k linii pe strict: true în tsconfig, consola a explodat: peste 200 de erori dintr-un foc. Te ia puțin panica, dar te prinzi repede că vreo 80% din ele sunt variații ale acelorași 5 greșeli.
Nu e nevoie să arunci cu any peste tot doar ca să scapi de sublinierea roșie. Iată erorile clasice și cum se rezolvă elegant.
1. useState inițializat cu null sau array gol
Dacă scrii const [user, setUser] = useState(null), TypeScript deduce tipul ca fiind null. Când încerci mai târziu să faci setUser({ name: 'Dan' }), primești eroare că obiectul nu e asignabil tipului null.
La fel pățești la array-uri: useState([]) devine never[], adică nu vei putea adăuga niciun element în el niciodată.
Soluția: Folosește mereu generice explicite când starea inițială e goală sau null:
const [user, setUser] = useState<User | null>(null);
const [items, setItems] = useState<string[]>([]);
2. Tiparea lui children în componente
Mulți folosesc JSX.Element pentru props-ul children. Problema apare când trimiți ca child un string simplu, un număr sau un fragment — JSX.Element acceptă doar elemente React valide, nu primitive.
Cealaltă extremă e helper-ul PropsWithChildren<T>, dar acesta face children opțional în mod implicit, ceea ce uneori maschează bug-uri dacă componenta ta chiar are nevoie de conținut.
Soluția: Pune direct children: React.ReactNode în interfața de props. E cel mai permisiv și corect tip pentru orice poate fi randat în React.
3. useRef legat la elemente din DOM
Eroarea clasică aici este Cannot assign to 'current' because it is a read-only property sau Property does not exist on type 'never'. Se întâmplă dacă scrii useRef() fără parametri sau fără tipul HTML-ului respectiv.
Soluția: Pasează tipul exact de element DOM și inițializează mereu cu null:
const inputRef = useRef<HTMLInputElement>(null);
Inițializarea cu null îi spune lui TypeScript că acel ref va fi atașat unui element din DOM gestionat de React (deci React se va ocupa de mutarea valorii lui current).
4. Tiparea evenimentelor (onChange, onSubmit)
Cea mai mare tentație când ești la început e să pui (e: any) => ... la handlere pentru că nu știi pe de rost denumirile din React. Pierzi însă tot autocompletion-ul util (e.target.value, e.preventDefault()).
Soluția: Formula e simplă: React.[NumeEveniment]Event<TipElementHTML>.
- Pentru input text:
ChangeEvent<HTMLInputElement> - Pentru formular:
FormEvent<HTMLFormElement> - Pentru butoane:
MouseEvent<HTMLButtonElement>
5. 'Object is possibly undefined' la props opționale
Când declari o proprietate ca fiind opțională (onClick?: () => void), TypeScript te va bloca dacă încerci să o apelezi direct cu onClick().
Soluția: Nu folosi non-null assertion operator (onClick!()) doar ca să tacă compilatorul — dacă prop-ul chiar lipsește la runtime, crapă aplicația. Folosește optional chaining: onClick?.() sau un guard clasic if (onClick) onClick().
TypeScript strict încetinește puțin ritmul în primele două săptămâni, dar te scapă de crash-uri banale în producție. Voi ce eroare de TS ați urât cel mai mult când ați început?