🧭 Introduction
In the previous lesson, you learned the fundamentals of TypeScript in React — typing props, state, events, and context.
But senior React developers go further.
They use advanced TypeScript patterns to:
- Build scalable component APIs
- Create reusable and flexible components
- Catch complex bugs at compile time
- Improve developer experience dramatically
This lesson focuses on practical TypeScript patterns used in real-world React applications, not theoretical complexity.
🎯 What You’ll Learn in This Lesson
By the end of this lesson, you will understand:
- Advanced prop typing techniques
- Union and discriminated union patterns
- Generics in React components
- Utility types in real React use cases
- Polymorphic components
- Common pitfalls and best practices
🧠 Why Advanced TypeScript Matters in React
Without advanced typing:
- Props become loosely defined
- Components accept invalid combinations
- Bugs slip into production
With advanced typing:
- Invalid usage fails at compile time
- Component APIs become self-documenting
- Refactoring is safe and predictable
🧩 Union Types for Props
Union types restrict values to a fixed set.
Example — Status Badge
type Status = "success" | "error" | "warning";
type BadgeProps = {
status: Status;
};
function Badge({ status }: BadgeProps) {
return <span>{status}</span>;
}
Now:
❌ <Badge status="loading" />
✅ Compile-time error
🧠 Discriminated Union (Very Important Pattern)
This pattern ensures valid prop combinations.
Example — Alert Component
type SuccessAlert = {
type: "success";
message: string;
};
type ErrorAlert = {
type: "error";
errorCode: number;
};
type AlertProps = SuccessAlert | ErrorAlert;
function Alert(props: AlertProps) {
if (props.type === "success") {
return <p>{props.message}</p>;
}
return <p>Error code: {props.errorCode}</p>;
}
✔ Type-safe branching
✔ Impossible invalid combinations
🧠 Generics in React Components
Generics make components reusable across data types.
Example — Generic List Component
type ListProps<T> = {
items: T[];
renderItem: (item: T) => React.ReactNode;
};
function List<T>({ items, renderItem }: ListProps<T>) {
return <ul>{items.map(renderItem)}</ul>;
}
Usage
<List
items={[1, 2, 3]}
renderItem={(n) => <li>{n}</li>}
/>
<List
items={[{ id: 1, name: "Avni" }]}
renderItem={(user) => <li>{user.name}</li>}
/>
✔ Fully type-safe
✔ Highly reusable
🧠 Typing API Responses with Generics
async function fetchData<T>(url: string): Promise<T> {
const res = await fetch(url);
return res.json();
}
Usage
type User = { id: number; name: string };
const users = await fetchData<User[]>("/api/users");
✔ No any
✔ API contracts enforced
🧠 Utility Types (Used in Real Apps)
Partial<T> — Optional Fields
type User = {
name: string;
email: string;
};
type UpdateUser = Partial<User>;
Useful for update forms.
Pick<T, K> — Select Fields
type UserPreview = Pick<User, "name">;
Omit<T, K> — Remove Fields
type PublicUser = Omit<User, "email">;
Record<K, T> — Key-Value Maps
type RolePermissions = Record<string, string[]>;
🧠 Polymorphic Components (Advanced Pattern)
Polymorphic components change behavior via props.
Example — Button or Link
type ButtonProps =
| { as: "button"; onClick: () => void }
| { as: "link"; href: string };
function Button(props: ButtonProps) {
if (props.as === "link") {
return <a href={props.href}>Link</a>;
}
return <button onClick={props.onClick}>Button</button>;
}
TypeScript ensures:
hrefonly exists for linksonClickonly exists for buttons
🧠 Typing Custom Hooks with Generics
function useAsync<T>(asyncFn: () => Promise<T>) {
const [data, setData] = React.useState<T | null>(null);
useEffect(() => {
asyncFn().then(setData);
}, []);
return data;
}
Usage
const users = useAsync<User[]>(fetchUsers);
🚨 Advanced TypeScript Mistakes to Avoid
❌ Overengineering Types
If types are harder than logic, simplify.
❌ Using any to Escape Errors
Fix the type instead.
❌ Creating God Types
Split large types into smaller ones.
❌ Blindly Copying Complex Patterns
Understand before using.
🎯 Best Practices (Senior-Level)
✅ Use discriminated unions for props
✅ Use generics for reusable components
✅ Type public APIs strictly
✅ Keep types readable
✅ Prefer correctness over cleverness
✅ Let TypeScript guide design
❓ FAQs — Advanced TypeScript in React
🔹 Is advanced TypeScript mandatory?
No, but extremely valuable for large apps.
🔹 Should beginners use these patterns?
Gradually — not all at once.
🔹 Are these patterns used in real companies?
Yes — heavily in design systems and shared libraries.
🔹 Is this asked in interviews?
Yes — especially for senior roles.
🧠 Quick Recap
✔ Union & discriminated union types improve safety
✔ Generics enable reuse
✔ Utility types simplify transformations
✔ Polymorphic components improve APIs
✔ Advanced typing = fewer bugs
🎉 Conclusion
Advanced TypeScript patterns turn React code into:
- Self-documenting APIs
- Compile-time safe systems
- Scalable architectures
Mastering these patterns means:
You’re not just writing React —
you’re designing systems.
This completes SECTION 10 — TypeScript with React 🔷⚛️
👉 Next Section
SECTION 11 — Advanced React Projects
👉 Next Lesson
Project 1 — Advanced Admin Dashboard