TypeScript has become the de facto standard for modern React development. Here are some practical tips to help you write better TypeScript code in your React projects.
1. Use Interface for Props
Always define interfaces for your component props:
interface ButtonProps {
label: string;
onClick: () => void;
variant?: 'primary' | 'secondary';
disabled?: boolean;
}
export const Button: React.FC<ButtonProps> = ({
label,
onClick,
variant = 'primary',
disabled = false
}) => {
return (
<button
onClick={onClick}
disabled={disabled}
className={`btn btn-${variant}`}
>
{label}
</button>
);
};
2. Leverage Type Inference
Let TypeScript infer types when possible:
// Good - TypeScript infers the type
const [count, setCount] = useState(0);
// Unnecessary - only specify when needed
const [count, setCount] = useState<number>(0);
// Necessary - when initial value is null/undefined
const [user, setUser] = useState<User | null>(null);
3. Use Discriminated Unions
For state management with different states:
type LoadingState =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: User }
| { status: 'error'; error: string };
function UserProfile({ state }: { state: LoadingState }) {
switch (state.status) {
case 'idle':
return <div>Click to load</div>;
case 'loading':
return <div>Loading...</div>;
case 'success':
return <div>Hello, {state.data.name}!</div>;
case 'error':
return <div>Error: {state.error}</div>;
}
}
4. Type Event Handlers Properly
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value);
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// handle form submission
};
5. Use Generics for Reusable Components
interface 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>
);
}
Conclusion
TypeScript might seem like extra work at first, but it pays dividends in catching bugs early, providing better IDE support, and making refactoring safer. Start with these patterns and gradually incorporate more advanced TypeScript features as you become comfortable.
Happy typing! 🎯