0Pricing
TypeScript Academy · Lesson

Component generics — intro

Build reusable components with type parameters, constraints, and inference; pass typed render props and keys safely.

Component generics — intro is a free TypeScript Academy lesson on CoddyKit — lesson 3 of 3. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the TypeScript Academy learning path, one of 3 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Intro

Goal: Make one component work for many data shapes using <T>. You will pass a typed render prop, constrain keys, and let TypeScript infer T from usage.

  • Generic props and render functions
  • Constraints with extends
  • Key extraction without any

Generic List<T>

A generic List<T> keeps items and render aligned. Consumers can pass any T; inference works when T is obvious.

import React from "react"

type ListProps<T> = { items: T[]; render: (item: T, index: number) => React.ReactNode }

export function List<T>({ items, render }: ListProps<T>) {
  return <div style={{ display: "grid", gap: 6 }}>{items.map(render)}</div>
}

export default function App() {
  return (
    <div style={{ display: "grid", gap: 12 }}>
      <List<number> items={[1,2,3]} render={(n) => <span>#{n}</span>} />
      <List<{ id: string; name: string }>
        items={[{ id: "u1", name: "Ada" }, { id: "u2", name: "Lin" }]}
        render={(u) => <strong>{u.name}</strong>}
      />
    </div>
  )
}

Constraints with extends

Use T extends Keyed to require an id for keys. Callers get errors if they pass items without the required field.

import React from "react"

type Keyed = { id: string }

type KeyListProps<T extends Keyed> = { items: T[]; render: (item: T) => React.ReactNode }

export function KeyList<T extends Keyed>({ items, render }: KeyListProps<T>) {
  return (
    <ul>
      {items.map((x) => (
        <li key={x.id}>{render(x)}</li>
      ))}
    </ul>
  )
}

export default function App() {
  const users = [{ id: "u1", name: "Ada" }, { id: "u2", name: "Lin" }]
  return <KeyList items={users} render={(u) => <span>{u.name}</span>} />
}

Inference of T

Type parameters usually infer from props: here, T comes from items. Only annotate when inference is unclear.

import React from "react"

type GridProps<T> = { items: T[]; columns?: number; render: (item: T) => React.ReactNode }

export function Grid<T>({ items, columns = 2, render }: GridProps<T>) {
  const css = { display: "grid", gridTemplateColumns: `repeat(${columns}, 1fr)`, gap: 8 }
  return <div style={css as React.CSSProperties}>{items.map(render)}</div>
}

export default function App() {
  const products = [
    { sku: "p1", title: "Mouse", price: 25 },
    { sku: "p2", title: "Keyboard", price: 80 }
  ]
  // T is inferred from products; no need to annotate
  return <Grid items={products} render={(p) => <span>{p.title} — ${p.price}</span>} />
}

Render helpers

Extract reusable Render<T> types for clarity. Constrain when necessary (T extends { id: string }) to support keys.

import React from "react"

type Render<T> = (item: T) => React.ReactNode

type TableProps<T extends { id: string }> = { items: T[]; renderRow: Render<T> }

export function Table<T extends { id: string }>({ items, renderRow }: TableProps<T>) {
  return (
    <table>
      <tbody>
        {items.map((x) => (
          <tr key={x.id}><td>{renderRow(x)}</td></tr>
        ))}
      </tbody>
    </table>
  )
}

export default function App() {
  const rows = [ { id: "1", label: "One" }, { id: "2", label: "Two" } ]
  return <Table items={rows} renderRow={(r) => <span>{r.label}</span>} />
}

Tips & gotchas

Tips:

  • Prefer inference; annotate only when it helps readability.
  • Constrain with extends to express requirements.
  • Avoid any in generic render props; it defeats safety.

Generics component check

Quick check: Which declaration correctly defines a generic React component?

Recap

Recap: Use <T> to build reusable components, constrain with extends for keys, and let inference keep code concise.

Frequently asked questions

Is the “Component generics — intro” lesson free?

Yes — the full text of “Component generics — intro” is free to read here on the web, and the TypeScript Academy course includes 3 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the TypeScript Academy course, upgrade to CoddyKit PRO.

What will I learn in “Component generics — intro”?

Build reusable components with type parameters, constraints, and inference; pass typed render props and keys safely. You practise TypeScript Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start TypeScript Academy?

No prior experience is required. TypeScript Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 3, so you can start here or from the beginning and move at your own pace.

How long does the “Component generics — intro” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this TypeScript Academy lesson?

Yes. Every TypeScript Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Props & children; event handlers; refs
  2. State & reducers; Context typing
  3. Component generics — intro
← Back to TypeScript Academy