TypeScript + React 🧠📘
TypeScript tightens React apps by catching type issues during development.
1) Typing Props & State ✅
type ButtonProps = {
label: string;
onPress?: () => void;
variant?: "primary" | "secondary";
};
function Button({ label, onPress, variant = "primary" }: ButtonProps) {
const className = variant === "primary" ? "btn-primary" : "btn-secondary";
return (
<button className={className} onClick={onPress}>
{label}
</button>
);
}- Use literal unions for variants.
- Infer state types from initial values, or annotate generics when needed:
const [items, setItems] = useState<Array<Todo>>([]);
2) Typing Events 🧠
- React wraps DOM events:
React.ChangeEvent,React.FormEvent, etc.
function SearchInput() {
const [value, setValue] = useState("");
function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
setValue(event.target.value);
}
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
console.log(value);
}
return (
<form onSubmit={handleSubmit}>
<input value={value} onChange={handleChange} />
</form>
);
}- For custom components, type callbacks:
onSelect?: (id: string) => void;
3) Generics with Components & Hooks ⚙️
- Write generic components when handling reusable data shapes.
type ListProps<T> = {
items: T[];
renderItem: (item: T) => React.ReactNode;
};
function List<T>({ items, renderItem }: ListProps<T>) {
return <ul>{items.map((item, index) => <li key={index}>{renderItem(item)}</li>)}</ul>;
}- Generic hooks capture reusable logic:
function usePrevious<T>(value: T) {
const ref = useRef<T>(value);
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}4) Discriminated Unions for UI States 🧩
Model UI status as a union to keep rendering logic exhaustive.
type AsyncState<T> =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: T }
| { status: "error"; error: string };
function DataPanel() {
const [state, setState] = useState<AsyncState<User>>({ status: "idle" });
if (state.status === "idle") return <p>Start searching</p>;
if (state.status === "loading") return <p>Loading...</p>;
if (state.status === "error") return <p>❌ {state.error}</p>;
return <ProfileCard user={state.data} />;
}switchstatements can ensure exhaustive handling (default: neverpattern).
Key Takeaways ✅
- Type props with interfaces/unions; annotate state when inference fails.
- Use React event typings to access DOM-safe properties.
- Generics make reusable components and hooks type-safe.
- Discriminated unions turn UI status flags into explicit branches.
Recap 🔄
TypeScript complements React by catching prop mismatches, ensuring event correctness, and modeling UI states precisely. Lean on interfaces, generics, and unions to keep components predictable and self-documenting.
Last updated on