TypeScript Best Practices for React
Introduction
TypeScript has become the standard for building large-scale React applications. It provides type safety, better IDE support, and helps catch errors before they reach production. In this guide, we'll explore best practices for using TypeScript effectively with React.
Component Props Typing
Always type your component props explicitly. Use interfaces for object props and type aliases for simpler cases:
interface ButtonProps {
label: string;
onClick: () => void;
variant?: 'primary' | 'secondary';
disabled?: boolean;
}
function Button({ label, onClick, variant = 'primary', disabled }: ButtonProps) {
return (
);
}
Event Handlers
Use React's built-in event types for event handlers:
function handleChange(event: React.ChangeEvent) {
console.log(event.target.value);
}
function handleClick(event: React.MouseEvent) {
event.preventDefault();
}
Hooks Typing
useState
TypeScript can often infer useState types, but be explicit for complex types:
const [user, setUser] = useState(null);
const [count, setCount] = useState(0);
useRef
For refs that will hold DOM elements, use the appropriate element type:
const inputRef = useRef(null);
const divRef = useRef(null);
Custom Hooks
Type your custom hooks' return values explicitly:
function useCounter(initialValue: number = 0) {
const [count, setCount] = useState(initialValue);
const increment = useCallback(() => {
setCount(prev => prev + 1);
}, []);
return { count, increment } as const;
}
Generic Components
Use generics for reusable components that work with different data types:
interface ListProps {
items: T[];
renderItem: (item: T) => React.ReactNode;
}
function List({ items, renderItem }: ListProps) {
return (
{items.map((item, index) => (
- {renderItem(item)}
))}
);
}
API Response Typing
Create types for your API responses to ensure type safety throughout your application:
interface User {
id: number;
name: string;
email: string;
}
interface ApiResponse {
data: T;
status: number;
message: string;
}
async function fetchUser(id: number): Promise> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
Common Pitfalls to Avoid
- Using
any: Avoid usinganyas it defeats the purpose of TypeScript - Ignoring type errors: Fix type errors rather than suppressing them
- Over-typing: Let TypeScript infer types when possible
- Missing null checks: Always handle potentially null/undefined values
Type Utilities
Leverage TypeScript's utility types for common transformations:
type PartialUser = Partial;
type ReadonlyUser = Readonly;
type UserEmail = Pick;
type UserWithoutId = Omit;
Conclusion
Following TypeScript best practices in React will significantly improve your code quality and developer experience. Start with proper prop typing and gradually adopt more advanced patterns as your application grows. Remember, the goal is to catch errors early and make your code more maintainable.

