GitHub

TypeScript for React

How to type component props, event handlers, and hooks correctly. The contracts that prevent silent bugs.

01

Principle

Bugs caught at compile time cost nothing to fix. Bugs caught in production cost everything. TypeScript for React is not about learning the full TypeScript language — it is about writing the right contracts between your components so that mistakes are caught before the code even runs.

lightbulb

Start by typing your component props. If you can describe what a component accepts and returns, the rest of the types follow naturally.

02

Rules

  • check_circle
    interface for component propsUse interface to define component props. It is extendable and reads clearly as a contract.
  • check_circle
    type for unions and utilitiesUse type for union types, utility types, and function signatures — things that are not directly 'objects with fields'.
  • check_circle
    Never use anyany disables type checking completely. Use unknown and narrow it with type guards instead.
  • check_circle
    strict: true in tsconfigStrict mode enables the full set of type checks. Without it, TypeScript catches only the most obvious errors.
03

Pattern

components/UserCard.tsx — typed component
import type { ReactNode } from 'react';

// ✅ interface for component props
interface UserCardProps {
  name: string;
  email: string;
  role: 'admin' | 'editor' | 'viewer';  // union type
  isActive: boolean;
  onEdit: (id: string) => void;          // typed event handler
  children?: ReactNode;
}

// ✅ typed event handler
function handleClick(event: React.MouseEvent<HTMLButtonElement>) {
  event.preventDefault();
}

// ✅ typed useState
const [count, setCount] = useState<number>(0);

// ❌ never do this
const fetchUser = async (): Promise<any> => { ... }

// ✅ use unknown and narrow
const fetchUser = async (): Promise<unknown> => { ... }
04

Implementation

info

Version Compatibility

Requires React 19+ and the latest stable versions of all dependencies shown.

Next.js page components receive typed params and searchParams. Always type these explicitly.

app/users/[id]/page.tsx
// ✅ Typed Next.js page props
interface PageProps {
  params: Promise<{ id: string }>;
  searchParams: Promise<{ tab?: string }>;
}

export default async function UserPage({ params }: PageProps) {
  const { id } = await params;
  return <UserDetail id={id} />;
}

// ✅ Typed Server Action
async function updateUser(
  id: string,
  data: UpdateUserInput
): Promise<{ success: boolean }> {
  'use server';
  // ...
}
menu_book
React Patterns

Helping developers build robust React applications since 2025.

© 2025 React Patterns Cookbook. Built with ❤️ for the community.
react-principles