import React, { useState, useRef } from 'react';
interface User {
id: number;
name: string;
}
export const UserForm = () => {
const [user, setUser] = useState<User | null>(null);
const inputRef = useRef<HTMLInputElement>(null);
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setUser({
id: 1,
name: e.target.value
});
};
const focusInput = () => {
inputRef.current?.focus();
};
const inlineStyles: React.CSSProperties = {
display: 'flex',
flexDirection: 'column'
};
return (
<div style={inlineStyles}>
<input ref={inputRef} onChange={handleInputChange} />
<button onClick={focusInput}>Focus</button>
{user && <p>Utilizator: {user.name}</p>}
</div>
);
};Trecerea la TypeScript strict în React pare o idee excelentă până când dai de primul val de erori roșii în editor. Am pățit-o acum vreo șase ani pe un proiect măricel, unde am pierdut două zile doar ghicind tipurile pentru evenimente. Ghidul ăsta te ajută să treci rapid peste cele mai enervante 5 erori de început fără să capitulezi și să pui any peste tot.
1. Children implicitly has an 'any' type
E clasică. Scrii o componentă de tip wrapper, destructurezi { children } și TypeScript începe să urle. În modul strict, parametrii funcțiilor nu pot avea un tip implicit.
Soluția corectă este să definim tipul props-urilor. Poți folosi React.ReactNode pentru copii. Personal, prefer să fiu explicit:
type LayoutProps = {
children: React.ReactNode;
};
Trade-off: Există și utilitarul PropsWithChildren, dar mie nu-mi place pentru că face children opțional prin definiție. Dacă layout-ul tău chiar are nevoie de acei copii ca să randeze ceva util, e mult mai sigur să îi pui manual ca fiind obligatorii.
2. Parameter 'e' implicitly has an 'any' type (la evenimente)
Ai un input simplu, pui un handler inline onChange={(e) => handleSearch(e)} și editorul se înroșește. TS nu știe ce fel de eveniment e ăla pentru că React folosește propriul sistem de evenimente peste cel nativ din browser (SyntheticEvents).
Nu pune any aici. Rezolvarea e simplă dacă folosești tipurile native din React: React.ChangeEvent<HTMLInputElement>. La o aplicație cu 15k utilizatori activi pe lună unde aveam formulare dinamice complexe, tipizarea corectă a evenimentelor ne-a salvat de zeci de bug-uri stupide de mapare a datelor.
3. Object is possibly 'null' la useRef
Vrei să pui focusul pe un input folosind un ref. Scrii const inputRef = useRef(null) și când apelezi inputRef.current.focus(), primești eroare.
DOM-ul nu este disponibil la prima randare, deci current chiar poate fi null inițial. Soluția elegantă este optional chaining: inputRef.current?.focus(). De asemenea, când definești ref-ul, spune-i explicit ce element HTML va găzdui: useRef<HTMLInputElement>(null).
4. Property 'name' does not exist on type 'never' (la useState)
Scrii const [user, setUser] = useState() și mai târziu încerci să faci setUser({ name: 'Andrei' }). TS o să zică că tipul trimis nu e compatibil cu undefined sau never.
Dacă nu-i dai o valoare inițială, TS nu are de unde să ghicească ce vrei să pui acolo. Folosește un generic: useState<User | null>(null). Îi spui practic compilatorului: "vezi că starea asta poate fi ori un obiect de tip User, ori null la început".
5. Type 'string' is not assignable to type 'Properties' (la stiluri inline)
Vrei să pasezi un obiect de stiluri ca prop: <div style={customStyles}>. Dacă customStyles e un obiect simplu, TS s-ar putea să plângă că proprietăți precum display au primit un string general, nu valorile stricte permise în CSS (cum ar fi 'flex' sau 'grid').
Soluția e să tipizezi obiectul cu React.CSSProperties. Așa primești și autocompletion excelent în editor pentru toate proprietățile CSS.
Voi cum ați gestionat tranziția asta? Ați fost tentați să puneți any peste tot în prima săptămână?