TypeScript Tips for React Developers
TypeScript brings type safety to JavaScript, making your React applications more robust and maintainable.
Strong Typing with React Components
Define component props with interfaces:
interface ButtonProps {
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
children: React.ReactNode;
variant?: 'primary' | 'secondary';
}
export const Button: React.FC<ButtonProps> = ({
onClick,
children,
variant = 'primary'
}) => {
return (
<button onClick={onClick} className={`btn-${variant}`}>
{children}
</button>
);
};
Generics for Reusable Components
Use generics to create flexible, type-safe components:
interface ListProps<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
}
export function List<T extends { id: string | number }>({
items,
renderItem,
}: ListProps<T>) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>{renderItem(item)}</li>
))}
</ul>
);
}
Type-Safe Hooks
Create custom hooks with proper typing:
function useAsync<T>(
asyncFunction: () => Promise<T>,
immediate = true,
): {
status: "idle" | "pending" | "success" | "error";
value: T | null;
error: Error | null;
} {
const [status, setStatus] = React.useState<
"idle" | "pending" | "success" | "error"
>("idle");
const [value, setValue] = React.useState<T | null>(null);
const [error, setError] = React.useState<Error | null>(null);
const execute = React.useCallback(async () => {
setStatus("pending");
try {
const response = await asyncFunction();
setValue(response);
setStatus("success");
} catch (err) {
setError(err instanceof Error ? err : new Error(String(err)));
setStatus("error");
}
}, [asyncFunction]);
React.useEffect(() => {
if (immediate) {
execute();
}
}, [execute, immediate]);
return { status, value, error };
}
Key Takeaways
- Define interfaces for props - Ensures components are used correctly
- Use generics for reusability - Create flexible, type-safe components
- Type your hooks - Prevent bugs in custom hook logic
- Leverage union types - Express valid state combinations more clearly
TypeScript might add some boilerplate, but it pays off with fewer runtime errors and better IDE support!