Background
Joy Ogukah
Back to Blog
Web Development

TypeScript Best Practices for React

12/28/2025
7 min read

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 using any as 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.

© 2026 Joy Ogukah. All rights reserved.