Lesson 7 • Advanced
TypeScript with React ⚛️
Type your React components, props, hooks, and event handlers correctly — eliminate entire categories of runtime bugs in your React applications.
What You'll Learn in This Lesson
- • Type component props with interfaces and discriminated unions
- • Type
useState,useRef,useReducer, anduseContext - • Event handler types: click, change, submit, keyboard
- • Children typing with
React.ReactNode - • Type-safe forms and validation patterns
npm create vite@latest -- --template react-ts.1️⃣ Typing Props
Define prop interfaces for every component. TypeScript will enforce required props, validate types, and even autocomplete prop names in your IDE. Use discriminated unions for conditionally required props.
Try It: Component Props
Props interfaces, children, optional props, and discriminated unions
// Typing React Props
console.log("=== Component Props Interface ===");
console.log();
console.log("interface ButtonProps {");
console.log(" label: string;");
console.log(" onClick: () => void;");
console.log(" variant?: 'primary' | 'secondary' | 'danger';");
console.log(" disabled?: boolean;");
console.log(" icon?: React.ReactNode;");
console.log("}");
console.log();
console.log("const Button: React.FC<ButtonProps> = ({ label, onClick, variant = 'primary' }) => {");
console.log(" return <
...2️⃣ Typing Hooks
Most hooks infer types automatically, but nullable state, refs, and reducers benefit from explicit type annotations. Custom hooks with typed contexts provide type-safe global state.
Try It: Typed Hooks
useState, useRef, useReducer, useContext with full type safety
// Typing React Hooks
console.log("=== useState ===");
console.log();
console.log("// Type is inferred from initial value:");
console.log("const [count, setCount] = useState(0); // number");
console.log("const [name, setName] = useState(''); // string");
console.log("const [items, setItems] = useState<string[]>([]); // explicit generic");
console.log();
console.log("// Nullable state:");
console.log("const [user, setUser] = useState<User | null>(null);");
console.log("// user i
...3️⃣ Events & Forms
React provides specific event types for every handler. Typing them correctly gives you access to the right properties — e.target.value only works on ChangeEvent<HTMLInputElement>, not a generic event.
Try It: Events & Forms
Click, change, submit, keyboard events, and typed form state
// Typing Events and Forms
console.log("=== Event Handlers ===");
console.log();
console.log("// Click events:");
console.log("const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {");
console.log(" e.preventDefault();");
console.log(" console.log('Clicked at', e.clientX, e.clientY);");
console.log("};");
console.log();
console.log("// Input change events:");
console.log("const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {");
console.log(" setName(e.target.value);
...⚠️ Common Mistakes
React.FC unnecessarily — Modern React prefers regular function declarations with typed props. FC adds implicit children and complicates generic components.useState<User | null>(null) means you must check for null before accessing properties.📋 Quick Reference
| Pattern | Type |
|---|---|
| Component | (props: Props) => JSX.Element |
| Children | React.ReactNode |
| Click event | React.MouseEvent<HTMLButtonElement> |
| Change event | React.ChangeEvent<HTMLInputElement> |
| Ref | useRef<HTMLDivElement>(null) |
| Context | createContext<T | undefined>(undefined) |
🎉 Lesson Complete!
You can now build fully type-safe React apps! Next, learn TypeScript best practices for production codebases.
Sign up for free to track which lessons you've completed and get learning reminders.