React with TypeScript
Typing Props, Hooks, and Events in React functional components.
🧑🏫 Sabse pehle — simple mein samjho#
React components normally bas JavaScript functions hi hote hain. TypeScript in functions ko type-safe bana deta hai, khaas kar Props ko. Ek baar tumne bata diya ki Button component text (string) aur onClick (function) property lega, to parent component hamesha wahi paas karega. Agar kuch bhula, TS turant laal patti dikhayega.
Isse tumhare React apps mein runtime errors (jaise Cannot read property 'map' of undefined) 90% kam ho jate hain!
1. Typing Props#
To type Props, you create a type or an interface and pass it into the function parameters.
// The blueprint for the Props
type ButtonProps = {
text: string;
color?: "primary" | "secondary"; // Optional and Literal Union
onClick: () => void;
};
// The Component Function
function Button({ text, color = "primary", onClick }: ButtonProps) {
return (
<button className={`btn-${color}`} onClick={onClick}>
{text}
</button>
);
}
Note: In the past, many developers used React.FC<ButtonProps>. However, in modern React (TS), typing function arguments directly (like the example above) is considered standard and better. React.FC used to implicitly inject the children prop everywhere, which is now considered unsafe.
2. Typing Hooks (useState and useRef)#
useState#
TS is usually smart enough to infer the type based on useState's initial value (Inference!).
However, when the initial value is null or an empty array [], you must provide a Generic parameter <T>.
// Inference (TS knows it's a number)
const [count, setCount] = useState(0);
type User = { name: string; age: number };
// Explicit typing via Generics: "This will either be a User object or null"
const [user, setUser] = useState<User | null>(null);
// For an initially empty array:
const [usersList, setUsersList] = useState<User[]>([]);
useRef#
When selecting DOM elements, you have to explicitly declare which HTML element will be attached to the ref.
// Provided the HTMLInputElement type
const inputRef = useRef<HTMLInputElement>(null);
const focusInput = () => {
// Optional chaining is required here because the ref is initially null
inputRef.current?.focus();
};
return <input ref={inputRef} />;
3. Typing Events#
Form submit or button click events in React possess specific, dedicated types (e.g., React.MouseEvent, React.ChangeEvent).
function SearchBar() {
const [query, setQuery] = useState("");
// Event type specific to Inputs
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setQuery(event.target.value);
};
// Event type specific to Buttons
const handleSubmit = (event: React.MouseEvent<HTMLButtonElement>) => {
event.preventDefault(); // ✅ TS allows this because it recognizes the preventDefault method on the mouse event
console.log("Searching: ", query);
};
return (
<div>
<input type="text" onChange={handleChange} />
<button onClick={handleSubmit}>Search</button>
</div>
);
}
4. The children Prop#
If your component is designed to wrap other components (a Wrapper component), you should type the children prop as React.ReactNode.
type CardProps = {
title: string;
children: React.ReactNode; // Can be anything React is capable of rendering (strings, elements, arrays)
};
function Card({ title, children }: CardProps) {
return (
<div className="card">
<h2>{title}</h2>
<div className="content">{children}</div>
</div>
);
}