🟦 React with TypeScript
Estimated reading: 4 minutes 272 views

React Generics & Interfaces – Build Flexible & Type-Safe Components (2025 Guide)


Introduction – Why Use Generics & Interfaces in React?

When building scalable React applications, you need components and hooks that can handle different data types while maintaining type safety. TypeScript’s Generics and Interfaces help you:

  • Build reusable components (like lists, tables, and forms)
  • Create flexible custom hooks
  • Maintain strong typings across various use cases

In this guide, you’ll learn:

  • How to define and use generics in React components and hooks
  • When to use interface vs type
  • Best practices for building maintainable, generic UIs

1. What Are Generics in TypeScript?

Generics are type variables that allow you to parameterize a component, function, or hook over one or more types.

Basic Example:

function identity<T>(value: T): T {
  return value;
}

You can now call identity<string>('React') or identity<number>(42)
Keeps logic flexible without losing type safety


2. Generic React Functional Component

type ItemListProps<T> = {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
};

function ItemList<T>({ items, renderItem }: ItemListProps<T>) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{renderItem(item)}</li>
      ))}
    </ul>
  );
}

Usage:

<ItemList
  items={['React', 'Vue', 'Svelte']}
  renderItem={(item) => <strong>{item}</strong>}
/>

Works for string[], User[], Product[], etc.
Type-safe rendering of any data structure


3. Typing Custom Hooks with Generics

function useArray<T>(initial: T[]): [T[], (item: T) => void] {
  const [array, setArray] = useState(initial);
  const push = (item: T) => setArray((a) => [...a, item]);
  return [array, push];
}

Usage:

const [names, addName] = useArray<string>([]);
addName('React');

Makes hooks reusable for any type
Promotes DRY logic across features


4. Interface vs Type – When to Use

Featureinterfacetype
Extensibility Can be extended Can use intersection (&)
Declaration merging Supported Not supported
Unions Not supported directly Works well with union types
Use caseObjects, classesFunctions, primitives, unions

Example:

interface User {
  id: number;
  name: string;
}

type Admin = User & { role: 'admin' };

Use interface for public APIs and extending objects
Use type for unions, aliases, and function signatures


5. Generics with Form Components

type InputProps<T> = {
  value: T;
  onChange: (value: T) => void;
};

function Input<T>({ value, onChange }: InputProps<T>) {
  return (
    <input
      value={String(value)}
      onChange={(e) => onChange(e.target.value as T)}
    />
  );
}

Type-safe for string, number, etc.
Avoid casting where possibleβ€”use overloads for better safety


6. Generic Component with Constraints

type WithId = { id: string | number };

function ListWithKey<T extends WithId>({ items }: { items: T[] }) {
  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>{JSON.stringify(item)}</li>
      ))}
    </ul>
  );
}

T extends WithId enforces that all items have id
Prevents misuse at compile time


7. Generic Context Provider Example

const createGenericContext = <T extends unknown>() => {
  const context = React.createContext<T | undefined>(undefined);
  const useGenericContext = () => {
    const value = useContext(context);
    if (!value) throw new Error('Context not found');
    return value;
  };
  return [context.Provider, useGenericContext] as const;
};

Build reusable contexts for themes, auth, or data sources
Fully type-safe access to shared data


Best Practices

Best PracticeWhy It Helps
Use generics for reusable logicAvoids duplication of similar code
Use constraints (extends)Prevents misused types
Use type for flexible component propsEasier to combine and extend
Prefer interface for objects onlyEnables declaration merging
Combine with React.memo or FC as neededWorks well in scalable systems

Summary – Recap & Next Steps

TypeScript generics and interfaces empower React developers to write reusable, type-safe, and scalable components. Whether you’re typing props, hooks, or contextsβ€”generics make your code DRY and robust.

Key Takeaways:

  • Use <T> to make components/data generic
  • Combine generics with constraints (extends) to enforce shape
  • Use type for unions and props, interface for objects
  • Create reusable hooks, lists, forms, and contexts with generics

Real-World Relevance:
Used in component libraries like Chakra UI, Radix UI, and design systems like Microsoft Fluent UI for consistent, type-safe APIs.


FAQ Section

Can I use generics with React.FC?
Yes, but avoid FC for performance-critical or overly generic cases. Prefer explicitly typed functions.


What’s the best way to type reusable form inputs?
Use a generic prop (<T>) and define event/value typings accordingly. You can also combine with Zod/Yup for validation.


Should I prefer type or interface?
Use type for component props, unions, and primitives. Use interface for extending object shapes or third-party integrations.


Can generics be used in JSX elements?
Yes, but the syntax can be tricky. Use parentheses or helper components to avoid ambiguity:

<ItemList<string> items={['a', 'b']} renderItem={...} />

What’s the benefit of constraints in generics?
They ensure generic types meet required conditions (e.g., extends { id: string }), reducing runtime errors.


Share Now :
Share

🟦 React Generics & Interfaces

Or Copy Link

CONTENTS
Scroll to Top