TypeScript with React
50 minTypeScript and React form a powerful combination that brings type safety to component-based UI development. By typing React components, props, state, and event handlers, you can catch errors at compile time that would otherwise only appear at runtime. This significantly improves developer experience, code quality, and maintainability of React applications.
React components can be typed using function component syntax with explicit prop types. The `React.FC` (or `React.FunctionComponent`) type is a generic type that accepts a props interface. However, many developers prefer explicit typing without `React.FC` for better control and to avoid some of its quirks. Both approaches work, but explicit typing gives you more flexibility.
Props are typically defined using interfaces or type aliases. Props interfaces should clearly describe what data and callbacks a component expects. Optional props are marked with `?`, and you can use union types for props that can be one of several values. Default props can be handled using default parameters or the `defaultProps` property, though default parameters are generally preferred in modern React.
Event handlers in React need proper typing for their event parameters. React provides specific event types like `React.MouseEvent<HTMLButtonElement>`, `React.ChangeEvent<HTMLInputElement>`, and `React.FormEvent<HTMLFormElement>`. These generic types ensure type safety for event properties like `event.target.value` or `event.preventDefault()`. Properly typing event handlers prevents common runtime errors.
Hooks in TypeScript require careful typing. `useState` can infer types from initial values, but you may need explicit typing for complex states or when the initial value is `null`. `useRef` requires a generic type parameter to specify what the ref will point to. `useCallback` and `useMemo` benefit from explicit return types when the inference isn't clear. Custom hooks should have proper return types for better developer experience.
Generic React components enable you to create reusable components that work with different data types. For example, a `List<T>` component can render lists of any type while maintaining type safety. Generic components are powerful for building component libraries and reusable UI patterns. TypeScript's generic system works seamlessly with React's component model.
Key Concepts
- TypeScript provides type safety for React components, props, and state.
- Props are defined using interfaces or type aliases.
- Event handlers need specific React event types for type safety.
- Hooks require proper typing for state, refs, and callbacks.
- Generic components enable type-safe reusable components.
Learning Objectives
Master
- Typing React components and their props
- Using React event types for type-safe event handlers
- Typing React hooks (useState, useRef, useCallback, useMemo)
- Creating generic React components for reusability
Develop
- Type-safe React development practices
- Understanding React's type system integration
- Designing maintainable component APIs with types
Tips
- Define prop types using interfaces for better IntelliSense and documentation.
- Use React's specific event types (React.MouseEvent, React.ChangeEvent) for event handlers.
- Type useState explicitly when the initial value doesn't provide enough type information.
- Use generic components for reusable, type-safe UI patterns.
Common Pitfalls
- Using any type for props, defeating TypeScript's purpose.
- Not typing event handlers, leading to runtime errors.
- Forgetting to type refs, causing null reference errors.
- Overcomplicating component types when simple types would suffice.
Summary
- TypeScript brings compile-time type safety to React development.
- Props should be typed using interfaces or type aliases.
- React provides specific event types for type-safe event handling.
- Hooks require proper typing for state, refs, and callbacks.
- Generic components enable type-safe reusable UI patterns.
Exercise
Create a TypeScript React component with proper type definitions.
import React from 'react';
interface ButtonProps {
text: string;
onClick: () => void;
disabled?: boolean;
variant?: 'primary' | 'secondary';
}
const Button: React.FC<ButtonProps> = ({
text,
onClick,
disabled = false,
variant = 'primary'
}) => {
return (
<button
onClick={onClick}
disabled={disabled}
className={`btn btn-${variant}`}
>
{text}
</button>
);
};
// Usage
<Button
text="Click me"
onClick={() => console.log('clicked')}
variant="secondary"
/>
Exercise Tips
- Use React.FC or define function components with explicit return types.
- Type event handlers: onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
- Use generic components: function List<T>({ items, render }: ListProps<T>) { ... }
- Type refs: const inputRef = useRef<HTMLInputElement>(null);