import React, { useState, useRef, ChangeEvent } from 'react';
interface UserFormProps {
initialName?: string;
onSubmit: (name: string) => void;
}
export const UserForm = ({ initialName = '', onSubmit }: UserFormProps) => {
const [name, setName] = useState<string>(initialName);
const inputRef = useRef<HTMLInputElement>(null);
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setName(e.target.value);
};
const handleFocus = () => {
inputRef.current?.focus();
};
return (
<div>
<input ref={inputRef} value={name} onChange={handleChange} />
<button onClick={handleFocus}>Focus</button>
<button onClick={() => onSubmit(name)}>Salvează</button>
</div>
);
};Dacă ai trecut recent un proiect de React pe strict: true în tsconfig.json, probabil ai impresia că TypeScript îți vrea doar răul. Am trecut prin asta prin 2018 pe o aplicație cu vreo 15k useri activi, când după o configurare de strictness jumătate din codebase s-a înroșit instant.
Partea bună e că 90% din erorile de la început se repetă obsesiv. Partea proastă e că dacă le rezolvi rapid cu any, mai bine rămâi pe JavaScript vanilla. Iată cele mai comune 5 erori și cum le rezolvi curat.
1. Binding element implicitly has an 'any' type
Apare imediat ce creezi o componentă și destructurezi props-urile fără să le dai un tip explicit. TypeScript refuză să ghicească ce proprietăți primește componenta ta.
Evită să folosești React.FC doar ca să scapi de eroare — versiunile vechi includeau children implicit, iar cele noi adaugă boilerplate inutil. Soluția curată e să declari o interfață simplă direct lângă componentă:
interface ButtonProps {
label: string;
onClick: () => void;
}
2. Property 'value' does not exist on type 'EventTarget'
Scrii un <input onChange={(e) => console.log(e.target.value)} /> inline și deodată e.target.value crapă la compilare. De ce? În DOM, e.target este un EventTarget generic, care poate fi o fereastră, un document sau un element SVG — chestii care nu au proprietatea value.
Trebuie să specifici tipul evenimentului folosind generics-urile oferite de React: React.ChangeEvent<HTMLInputElement>. Așa TS știe exact că e.target este un element de tip input HTML.
3. Type 'null' is not assignable to type 'HTMLInputElement'
Când scrii const inputRef = useRef(null);, TypeScript inferă că ref-ul va fi exclusiv null pe toată durata de viață a componentei. Dacă încerci să-l pui pe un <input ref={inputRef} />, primești eroare de tip.
Trimiterea tipului DOM în generic rezolvă problema: useRef<HTMLInputElement>(null). De asemenea, când apelezi inputRef.current.focus(), compilatorul va țipa din nou dacă nu folosești optional chaining (inputRef.current?.focus()), pentru că ref-ul e null la prima randare.
4. Object is possibly 'undefined'
Ai o interfață cu o proprietate opțională, de exemplu user?: { name: string }. Când încerci să afișezi user.name, TypeScript te oprește.
Am văzut mulți developeri la început de drum rezolvând asta cu operatorul non-null assertion: user!.name. Nu face asta decât dacă ești 100% sigur că valoarea e prezentă. În 99% din cazuri, soluția corectă este safe navigation (user?.name) sau un early return (if (!user) return null;).
5. Array-ul gol din useState inferat ca 'never[]'
Dacă scrii const [items, setItems] = useState([]);, TS va presupune că items este un tablou care va rămâne mereu gol (never[]). Când încerci mai târziu să faci setItems([{ id: 1 }]), primești eroare.
Când starea inițială e un tablou gol sau null, trebuie să treci tipul explicit în useState: useState<Item[]>([]) sau useState<User | null>(null).
Trade-off-ul din spatele modului strict
Da, în primele 2-3 săptămâni vei scrie cod cu 20-30% mai încet. E super enervant când vrei doar să testezi o idee și pierzi 10 minute căutând tipul corect pentru un event de Drag and Drop. Însă pe termen lung, strictness-ul elimină aproape complet erorile penibile de Cannot read property of undefined în producție.
Voi de care dintre erorile astea v-ați lovit cel mai des când ați făcut trecerea?