import React, { useState, useRef, ChangeEvent } from 'react';
interface User {
id: number;
name: string;
}
export const UserForm = () => {
// Fix 1: Tipizare explicită pentru array gol
const [users, setUsers] = useState<User[]>([]);
// Fix 3: Ref inițializat cu null și tipizat
const inputRef = useRef<HTMLInputElement>(null);
// Fix 2: ChangeEvent specific pentru HTMLInputElement
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value);
};
const handleFocus = () => {
// Fix 3: Optional chaining împotriva crash-urilor
inputRef.current?.focus();
};
return (
<div>
<input ref={inputRef} onChange={handleChange} />
<button onClick={handleFocus}>Focus</button>
</div>
);
};Când treci de la JS pur la React cu TypeScript și bifezi strict: true în tsconfig.json, zici că nimerești într-un zid. Am pățit-o acum vreo 5 ani când am trecut prima dată o aplicație cu vreo 15k useri lunari pe TS — am avut 140 de erori la primul npm run build și mi-a luat 4 ore doar să înțeleg de ce țipa compilatorul.
Partea bună e că 90% din ele sunt aceleași 5 tipare obositoare. Hai să le luăm pe rând ca să nu pierzi timp aiurea pe StackOverflow cum am făcut eu.
1. Type 'string' is not assignable to type 'never'
Asta apare aproape mereu când declari un state cu un array gol: const [items, setItems] = useState([]). TypeScript nu are de unde să știe ce o să pui în lista aceea mai târziu, așa că deduce că e de tip never[]. Când faci un setItems(['demo']), crapă build-ul.
Soluția e simplă: precizează tipul generic direct la apelare: useState<string[]>([]) sau useState<User[]>([]) dacă ai o interfață.
2. EventTarget nu are proprietatea 'value'
Scrii un onChange rapid pe un <input> și încerci să citești e.target.value. Compilerul îți dă cu flit pentru că, implicit, e este un eveniment generic unde target nu are neapărat o proprietate value (gândește-te la un click pe un div).
Tratamentul curat este să tipizezi explicit parametrul: (e: React.ChangeEvent<HTMLInputElement>) => void. Așa TS știe exact că e.target este un element de HTML de tip input care are garantat proprietatea .value.
3. Object is possibly 'null' la useRef
Inițializezi un ref pentru un input: const inputRef = useRef<HTMLInputElement>(null). Când vrei să apelezi inputRef.current.focus(), TypeScript te oprește pe bună dreptate: la prima randare, .current chiar este null.
Aici ai două opțiuni. Fie folosești optional chaining (inputRef.current?.focus()), fie pui un guard clasic if (inputRef.current). Trade-off-ul? Optional chaining e mai scurt și mai elegant, dar dacă uiți să-l pui unde trebuie, TS te va certa din nou. Nu folosi inputRef.current!.focus() (non-null assertion) decât dacă ești 100% sigur pe ce faci — e doar o cale de a păcăli compilatorul și poți da de runtime errors.
4. Element implicitly has an 'any' type
Ai un obiect de configurare și încerci să accesezi o cheie dinamică: CONFIG[myKey], unde myKey e declarat ca string. TS se plânge că string-ul tău poate fi absolut orice text, nu doar o cheie validă din CONFIG.
Ca să scapi de eroare fără să pui any, trebuie să-i spui compilatorului că myKey este strict o cheie a acelui obiect: CONFIG[myKey as keyof typeof CONFIG].
5. Type 'Props' is not assignable / Destructuring la children
Când creezi un component funcțional și destructurezi props-urile ({ title, children }), TS nu știe ce e children. În versiunile vechi de React se folosea React.FC, dar azi comunitatea evită asta pentru că adăuga children implicit peste tot, chiar și la componente care nu ar fi trebuit să aibă copii.
Varianta modernă și sigură e să-ți definiești clar interfața de Props folosind helper-ul dedicat: type CardProps = React.PropsWithChildren<{ title: string }>;.
Concluzie
Strict mode în TypeScript pare frustrant la început și îți scade viteza în primele două săptămâni cu vreo 20%. Însă după ce prinzi reflexele astea 5, scrii cod mult mai sigur și nu mai ai surprize cu undefined is not a function în producție.
Voi de ce erori de TS v-ați lovit cel mai des când ați trecut la React cu type checking?