P
Pixel Show
TypeScriptReact

TypeScript Patterns Every React Developer Needs

Practical TypeScript patterns for React — from component props to event handlers to generic components.

TypeScript Makes React Better

TypeScript catches prop errors at build time, provides autocompletion in your editor, and documents component APIs automatically. The investment pays off quickly.

Component Props

Define props with an interface or type:

interface ButtonProps {
  label: string
  variant?: 'primary' | 'secondary'
  onClick: () => void
}

function Button({ label, variant = 'primary', onClick }: ButtonProps) { return }

The question mark makes variant optional with a default value.

Children Prop

interface CardProps {
  children: React.ReactNode
  className?: string
}

React.ReactNode accepts any renderable content — strings, elements, arrays, fragments.

Event Handlers

Use the specific event type instead of any:

function SearchInput() {
  const handleChange = (e: React.ChangeEvent) => {
    console.log(e.target.value)
  }
  return 
}

Common types: ChangeEvent, MouseEvent, KeyboardEvent, FormEvent.

Extending HTML Elements

When your component wraps a native HTML element, extend its props:

interface InputProps extends React.InputHTMLAttributes {
  label: string
}

Now your component accepts all native input attributes plus your custom ones.

Generic Components

For components that work with different data types:

interface ListProps {
  items: T[]
  renderItem: (item: T) => React.ReactNode
}

function List({ items, renderItem }: ListProps) { return

    {items.map(renderItem)}
}

TypeScript infers T from usage — no manual type annotation needed at the call site.

State Types

Usually TypeScript infers state types from the initial value. Specify only when the initial value does not represent all possible states:

const [user, setUser] = useState(null)

Discriminated Unions for Component States

type State =
  | { status: 'loading' }
  | { status: 'error'; message: string }
  | { status: 'success'; data: Product[] }

TypeScript narrows the type when you check status, preventing you from accessing data on an error state.

Avoid These

  • any — defeats the purpose of TypeScript
  • Overly complex generic types — keep it readable
  • Type assertions (as) — usually a sign you need to fix the actual type
  • Exporting every type — only export what consumers need

Build websites faster

Staxl — premium templates for modern web projects

Explore Staxl →