DEV Community

Cover image for React TypeScript Best Practices: Complete Guide for Type-Safe React Applications
Md. Maruf Rahman
Md. Maruf Rahman

Posted on • Edited on • Originally published at practicaldev.online

React TypeScript Best Practices: Complete Guide for Type-Safe React Applications

When I first started using TypeScript with React, I thought it would just add extra typing overhead. Boy, was I wrong. TypeScript has saved me countless hours by catching bugs before they reach production, and it's made my codebase infinitely more maintainable. But using TypeScript effectively in React requires understanding some patterns and best practices that aren't always obvious.

TypeScript brings compile-time type checking to React, which means you catch errors while writing code, not when users report bugs. It also provides incredible IDE support—autocomplete, refactoring, and navigation all work better when TypeScript understands your code structure. But to get these benefits, you need to type your components, props, hooks, and event handlers correctly.

Why TypeScript with React?

TypeScript with React provides:

  • Type safety - Catch errors at compile time
  • Better IDE support - Autocomplete, IntelliSense, and refactoring
  • Self-documenting code - Types serve as documentation
  • Easier refactoring - TypeScript catches breaking changes
  • Better collaboration - Types help team members understand code
  • Runtime error prevention - Catch bugs before they reach production

Type Definitions for Props

Define component prop types using interfaces or types:

type Product = {
  id: string | number;
  name: string;
  price: number;
  stock: number;
  categoryId: number;
  categoryName?: string;
};

interface ProductCardProps {
  product: Product;
  onEdit?: (id: string | number) => void;
  onDelete?: (id: string | number) => void;
  showActions?: boolean;
}

function ProductCard({ 
  product, 
  onEdit, 
  onDelete, 
  showActions = true 
}: ProductCardProps) {
  return (
    <div className="product-card">
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      <p>Stock: {product.stock}</p>
      {showActions && (
        <div>
          {onEdit && <button onClick={() => onEdit(product.id)}>Edit</button>}
          {onDelete && <button onClick={() => onDelete(product.id)}>Delete</button>}
        </div>
      )}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Typing React Hooks

useState Hook

Type useState explicitly or let TypeScript infer:

// Explicit typing
const [name, setName] = useState<string>("");
const [count, setCount] = useState<number>(0);
const [products, setProducts] = useState<Product[]>([]);

// Type inference
const [isLoading, setIsLoading] = useState(false); // boolean
const [user, setUser] = useState<User | null>(null); // Better
Enter fullscreen mode Exit fullscreen mode

Custom Hooks

Create typed custom hooks:

type UseProductsReturn = {
  products: Product[];
  isLoading: boolean;
  isError: boolean;
  error: any;
  refetch: () => void;
};

function useProducts(): UseProductsReturn {
  const { data, isLoading, isError, error, refetch } = useGetProductsQuery({});

  return {
    products: data?.data || [],
    isLoading,
    isError,
    error,
    refetch,
  };
}
Enter fullscreen mode Exit fullscreen mode

Event Handlers

Type event handlers correctly:

// Form submit handler
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
  e.preventDefault();
  // Handle submission
};

// Button click handler
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
  // Handle click
};

// Input change handler
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  setValue(e.target.value);
};
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Use interfaces for component props
  2. Type useState explicitly when needed
  3. Create typed custom hooks
  4. Type event handlers correctly
  5. Use generics for reusable components
  6. Leverage type inference when possible

📖 Read the Complete Guide

This is just a brief overview! The complete guide on my blog includes:

  • Type vs Interface - When to use each
  • Generics in React - Reusable typed components
  • Context Types - Typing React Context
  • Ref Types - Typing useRef and refs
  • Higher-Order Components - Typing HOCs
  • Advanced Patterns - Utility types, conditional types
  • Real-world examples from production applications

👉 Read the full article with all code examples here


What's your experience with TypeScript and React? Share your tips in the comments! 🚀

For more React guides, check out my blog covering React Router, React Hook Form, Redux Toolkit, and more.

Top comments (0)