React Curriculum

Generic Components: Type-Safe Tables, Selects & Lists

Hard100% Free~30 mins#react#typescript#generics#table#design-systems#type-inference
Interview Answer (30-Second Summary)

Generic React components accept TypeScript type parameters `<T>`, enabling reusable UI primitives like Tables, Selects, and Virtual Lists to enforce full type safety on data items, callbacks, and custom cell renderers without losing type inference.

Key Learning Objectives
✓

Implement reusable generic React components using `<T>` type parameters.

✓

Enforce type inference on selection callbacks (e.g. `onSelect: (item: T) => void`).

✓

Design type-safe generic Table column definitions with keyed accessors and cell formatters.

✓

Apply generic constraints (`<T extends { id: string }>`) to enforce minimum data contracts.

The Interview Problem & Context

Build a fully type-safe generic `<Select>` component and `<DataTable>` component that infers item types automatically without requiring manual type casting.

1import React from 'react';
2
3// 1. Generic Select Component
4interface SelectProps<T> {
5 items: T[];
6 selectedItem: T | null;
7 onSelect: (item: T) => void;
8 getLabel: (item: T) => string;
9 getKey: (item: T) => string | number;
10}
11
12export function Select<T>({ items, selectedItem, onSelect, getLabel, getKey }: SelectProps<T>) {
13 return (
14 <ul role="listbox" className="select-list">
15 {items.map((item) => {
16 const isSelected = selectedItem ? getKey(selectedItem) === getKey(item) : false;
17 return (
18 <li
19 key={getKey(item)}
20 role="option"
21 aria-selected={isSelected}
22 onClick={() => onSelect(item)}
23 className={isSelected ? 'selected' : ''}
24 >
25 {getLabel(item)}
26 </li>
27 );
28 })}
29 </ul>
30 );
31}
32
33// 2. Generic Column Definition for DataTable
34export interface Column<T> {
35 header: string;
36 accessorKey?: keyof T;
37 render?: (item: T) => React.ReactNode;
38}
39
40interface DataTableProps<T extends { id: string | number }> {
41 data: T[];
42 columns: Column<T>[];
43}
44
45export function DataTable<T extends { id: string | number }>({ data, columns }: DataTableProps<T>) {
46 return (
47 <table className="data-table">
48 <thead>
49 <tr>
50 {columns.map((col, idx) => (
51 <th key={idx}>{col.header}</th>
52 ))}
53 </tr>
54 </thead>
55 <tbody>
56 {data.map((row) => (
57 <tr key={row.id}>
58 {columns.map((col, idx) => (
59 <td key={idx}>
60 {col.render
61 ? col.render(row)
62 : col.accessorKey
63 ? String(row[col.accessorKey])
64 : null}
65 </td>
66 ))}
67 </tr>
68 ))}
69 </tbody>
70 </table>
71 );
72}
Deep Architectural Explanation

How Generic React Components Work

When you write:

typescript
export function Select<T>({ items, onSelect }: SelectProps<T>) { ... }

TypeScript uses argument type inference:

  1. When you pass items={users} where users is User[], TypeScript binds T = User.
  2. onSelect is immediately inferred as (item: User) => void.
  3. Inside your callback onSelect={(u) => console.log(u.email)}, u is auto-completed with full User properties—zero manual type casting needed!

TSX Syntax Gotcha with Arrow Functions:

In .tsx files, arrow function generics can confuse the JSX parser:

typescript
// Syntax Error: JSX parser thinks <T> is an unclosed HTML tag!
const Select = <T>(props: SelectProps<T>) => ...

// Solution 1: Use function declaration
function Select<T>(props: SelectProps<T>) { ... }

// Solution 2: Add trailing comma or extends constraint
const Select = <T,>(props: SelectProps<T>) => ...
const Select = <T extends unknown>(props: SelectProps<T>) => ...
Common Interview Traps & Pitfalls
✕

Using `any[]` for reusable list or table data, throwing away type safety across the entire component.

✕

Getting tripped up by `.tsx` syntax errors when writing arrow function generics `<T>`.

✕

Over-constraining generic types unnecessarily, preventing primitive types (strings, numbers) from being used.

Senior Interviewer Follow-Up Probes
?

How do libraries like TanStack Table type deeply nested column accessor keys (e.g., `user.address.city`)?

?

How do you combine generic components with React.memo or forwardRef?

?

How can you enforce that at least one of `accessorKey` or `render` is provided in a column definition?

Frequently Asked Interview Questions
What is a generic component in React?

A component that accepts one or more TypeScript type parameters (<T>), allowing it to work with various data types while preserving full compile-time type safety and property auto-completion.

The TSX compiler interprets <T> as an opening JSX HTML tag. Adding a trailing comma (<T,>) or a constraint (<T extends unknown>) resolves the ambiguity.

TypeScript inspects the props passed to the component (like data or items) and automatically infers the generic type T. All associated callbacks (e.g., onSelect: (item: T) => void) inherit that inferred type.

Using extends (such as <T extends { id: string }>) to require that any data object passed into the component must contain specific properties (like an id for React keys).

Yes, but React.memo erases generic type parameters unless wrapped in a custom type assertion or helper function casting memo back to generic component signatures.

Whenever a component operates on collections of items (tables, dropdowns, auto-completes, virtual lists, paginators) and passes individual items back to consumer callbacks or render props.