import { useState, useRef, ChangeEvent, FormEvent } from 'react';
interface User {
id: number;
name: string;
}
export const UserForm = () => {
// 1. useState cu generic corect (fără never[])
const [users, setUsers] = useState<User[]>([]);
const [name, setName] = useState('');
// 2. useRef inițializat explicit
const inputRef = useRef<HTMLInputElement>(null);
// 3. Tipare corectă pentru onChange
const handleNameChange = (e: ChangeEvent<HTMLInputElement>) => {
setName(e.target.value);
};
// 4. Tipare corectă pentru onSubmit
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!name.trim()) return;
setUsers((prev) => [...prev, { id: Date.now(), name }]);
setName('');
// Optional chaining în loc de non-null assertion (!)
inputRef.current?.focus();
};
return (
<form onSubmit={handleSubmit}>
<input ref={inputRef} value={name} onChange={handleNameChange} />
<button type="submit">Adaugă</button>
</form>
);
};Când am activat prima dată "strict": true pe un proiect de React existent — un dashboard intern cu vreo 8k utilizatori activi — consola mea a explodat cu 140 de erori. Impulsul inițial a fost să pun // @ts-ignore peste tot sau să trântesc any, doar ca să treacă pipeline-ul de CI/CD.
E o greșeală clasică. Dacă știi exact de ce urlă compilatorul, majoritatea erorilor se rezolvă în câteva secunde.
1. useState([]) inițializat ca never[]
Scrii const [items, setItems] = useState([]); și două rânduri mai jos vrei să faci items.push(...) sau să accesezi items[0].id. Bum: Property 'id' does not exist on type 'never'.
TypeScript deduce tipul pe baza valorii inițiale. Pentru un array gol fără context, el deduce never[], adică o listă care nu poate conține niciodată nimic. Rezolvarea e să-i dai explicit generic-ul: useState<User[]>([]).
2. Evenimente de input netipate corect
La un simplu onChange, dacă lași parametrul e fără tip, TS strict aruncă Parameter 'e' implicitly has an 'any' type. Mulți pun e: any și merg mai departe, pierzând autocompletion-ul.
Soluția corectă este să folosești tipurile native din React: React.ChangeEvent<HTMLInputElement>. Dacă e pe form, ai React.FormEvent<HTMLFormElement>. Îți ia trei secunde să-l scrii și ai acces instant la e.currentTarget.value fără dubii.
3. Object is possibly 'null' la useRef
Când declari const inputRef = useRef<HTMLInputElement>(null);, TypeScript te obligă pe bună dreptate să verifici existența nodului din DOM înainte să-l accesezi. Dacă scrii direct inputRef.current.focus(), codul pică la compilare.
Soluția nu e operatorul ! de non-null assertion (inputRef.current!.focus()), deși îl văd des. Soluția sănătoasă e un simplu optional chaining: inputRef.current?.focus(). Dacă ref-ul nu e încă atașat, aplicația nu crapă în runtime.
4. Props opționale cu valori undefined
Dacă ai un prop marcat cu semnul întrebării (title?: string), iar componenta ta îl trimite mai departe într-o funcție care cere strict string, primești Type 'undefined' is not assignable to type 'string'.
În loc să faci casting forțat, rezolvă problema din destructurare cu o valoare default: const { title = 'Titlu implicit' } = props;. Din momentul ăla, TS știe sigur că title e garantat string în interiorul componentei.
5. Destructurarea proprietăților necunoscute
Când preiei date dintr-un API extern și le definești sumar, iar apoi încerci să accesezi o proprietate dinamică, TS se blochează dacă nu ai un index signature. În loc de Record<string, any>, recomand să folosești Record<string, unknown> combinat cu type guards simple sau biblioteci de validare la runtime gen Zod.
Merită efortul?
Strict mode te încetinește cu vreo 20-30% în primele zile când scrii cod, nu te mint. Dar la proiectul de care ziceam, numărul de bug-uri legate de date lipsă raportate în Sentry a scăzut aproape la zero după refactorizare. Nu mai ai surprize cu Cannot read properties of undefined în producție.
Voi cum ați făcut tranziția: ați pornit din start cu strict sau ați migrat treptat fișierele?