TypeScript Best Practices for React Applications
Explore essential TypeScript patterns and best practices that will make your React applications more maintainable and type-safe.
TypeScript, React, Best Practices
TypeScript Best Practices for React Applications
TypeScript has revolutionized the way we build React applications. In this post, I'll share some essential patterns and best practices I've learned.
Why TypeScript with React?
TypeScript brings several benefits to React development:
- Type Safety: Catch errors before runtime
- Better IDE Support: Autocomplete, refactoring, and navigation
- Self-Documenting Code: Types serve as inline documentation
- Easier Refactoring: Confidence when making changes
Component Props
Always define your component props with interfaces:
interface ButtonProps {
variant?: 'primary' | 'secondary';
size?: 'sm' | 'md' | 'lg';
onClick?: () => void;
children: React.ReactNode;
}
export function Button({
variant = 'primary',
size = 'md',
onClick,
children
}: ButtonProps) {
return (
<button
className={`btn-${variant} btn-${size}`}
onClick={onClick}
>
{children}
</button>
);
}
State Management
Use proper typing for state:
interface User {
id: string;
name: string;
email: string;
}
function UserProfile() {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState<boolean>(false);
// Your component logic here
}
Event Handlers
Type your event handlers correctly:
function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
console.log(event.target.value);
}
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
// Handle form submission
}
Custom Hooks
Create reusable, type-safe hooks:
function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(() => {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
});
const setStoredValue = (newValue: T) => {
setValue(newValue);
localStorage.setItem(key, JSON.stringify(newValue));
};
return [value, setStoredValue] as const;
}
Utility Types
Leverage TypeScript's utility types:
// Pick specific properties
type UserPreview = Pick<User, 'id' | 'name'>;
// Make all properties optional
type PartialUser = Partial<User>;
// Make all properties required
type RequiredUser = Required<User>;
// Omit specific properties
type UserWithoutEmail = Omit<User, 'email'>;
Conclusion
These TypeScript patterns will help you write more maintainable and type-safe React applications. Remember to always leverage TypeScript's type system to its full potential!