import { useState, ChangeEvent, PropsWithChildren } from 'react';
interface User {
id: string;
name: string;
}
type CardProps = PropsWithChildren<{
title: string;
}>;
export const UserCard = ({ title, children }: CardProps) => {
// 1. State generic cu unions
const [user, setUser] = useState<User | null>(null);
// 2. Event typat corect
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value);
};
return (
<div className="card">
<h3>{title}</h3>
{children}
<input type="text" onChange={handleInputChange} />
{user ? <p>Salut, {user.name}!</p> : <p>Neconectat</p>}
</div>
);
};Când bifezi strict: true în tsconfig.json pentru primul tău proiect de React, ecranul roșu din VS Code pare o pedeapsă. Am trecut și eu prin asta când am migrat un dashboard cu vreo 12k utilizatori activi de pe JS chior pe TS strict. Câștigi zeci de ore de refactoring mai târziu dacă înțelegi din start de ce țipă compilatorul la aceste 5 tipare uzuale.
1. FC nu mai include children din oficiu
Dacă ai învățat React + TS din tutoriale vechi, probabil scriai const Card: React.FC = ({ children }) => .... De la React 18 încoace, tipul React.FC nu mai include implicit prop-ul children. Compilatorul îți va arunca rapid eroarea Property 'children' does not exist on type....
Soluția curată este să folosești helper-ul PropsWithChildren din React sau să declari explicit children?: React.Node în interfața ta. Eu prefer PropsWithChildren pentru că păstrează codul curat și lizibil.
2. Event-urile scăpate de sub control în Form-uri
Cea mai frecventă greșeală în handlere este definirea parametrului de event fără tip: const handleChange = (e) => .... TypeScript va urla imediat din cauza opțiunii noImplicitAny.
Nu pune e: any doar ca să tacă compilatorul. Dacă faci asta, pierzi tot autocompletion-ul pentru e.target.value. Tipul corect pentru un input standard de text este React.ChangeEvent<HTMLInputElement>. Pentru submit de formular, folosești React.FormEvent<HTMLFormElement>.
3. State-ul inițializat cu null
Scrii const [user, setUser] = useState(null) și mai târziu în cod încerci să faci setUser(userData). Compilatorul îți dă cu flit: Argument of type 'User' is not assignable to parameter of type 'null'. TypeScript a dedus că state-ul tău va fi ÎNTOTDEAUNA null fiindcă nu i-ai dat un generic.
Specifică explicit tipurile alternative folosind Generics: useState<User | null>(null). Așa îi spui compilatorului că la început nu ai date, dar ulterior vei stoca un obiect de tip User.
4. useRef și eroarea Object is possibly 'null'
Când creezi un ref pentru un element DOM (const inputRef = useRef<HTMLInputElement>(null)), TypeScript știe că până se montează componenta, .current va fi null. Dacă încerci inputRef.current.focus(), build-ul crapă.
Ai două variante: verifici explicit starea (if (inputRef.current) inputRef.current.focus()) sau folosești optional chaining: inputRef.current?.focus(). A doua varianta e mult mai scurtă și e idiomatică în React modern.
5. Tentația de a trânti 'any' peste tot
Când ai un deadline strâns, e tentant să pui any la datele venite dintr-un API extern fără tipuri. E un trade-off acceptabil dacă trebuie să dai deploy la 5 după-amiaza pentru un hotfix. Totuși, dacă nu pui un // TODO să îl înlocuiești cu o interfață sau cu unknown, în câteva luni tot proiectul devine un JS cosmetizat și pierzi orice siguranță.
Voi cum ați gestionat tranziția la TypeScript strict în echipă? Ați migrat totul dintr-o dată sau fișier cu fișier?