Обобщения компонентов — введение
Создавайте повторно используемые компоненты с параметрами типов , ограничениями и выводом типов; безопасно передавайте типизированные render-пропы и ключи.
«Обобщения компонентов — введение» — бесплатный урок TypeScript Academy на CoddyKit. Это урок 3 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения TypeScript Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс TypeScript Academy содержит 3 уроков всего.
Введение
Цель: заставить один компонент работать с различными формами данных с помощью <T>. Вы передадите типизированное свойство отрисовки, ограничите ключи и позволите TypeScript вывести T из использования.
- Обобщённые свойства и функции отрисовки
- Ограничения с помощью
extends - Извлечение ключей без универсального типа
Обобщённый List<T>
Обобщённый List<T> поддерживает согласованность между элементами и отрисовкой. Потребители могут передать любой T; вывод типов работает, когда T очевиден.
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>
)
}Ограничения с extends
Используйте T extends Keyed, чтобы потребовать наличие id для ключей. При передаче элементов без обязательного поля вызывающий код получит ошибки.
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>} />
}Вывод T
Параметры типов обычно выводятся из свойств: здесь T берётся из items. Добавляйте аннотацию только при неясном выводе типов.
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<T>. При необходимости задавайте ограничение (T extends { id: string }), чтобы поддерживать ключи.
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>} />
}Советы и подводные камни
Советы:
- Предпочитайте вывод типов и добавляйте аннотации только для улучшения читаемости.
- Используйте
extendsдля выражения требований. - Избегайте
anyв обобщённых свойствах отрисовки: это лишает их безопасности.
Проверка компонентов с обобщениями
Быстрая проверка: какое объявление правильно определяет обобщённый React-компонент?
Повторение
Повторение: используйте <T> для создания повторно используемых компонентов, задавайте ограничения с помощью extends для ключей и позволяйте выводу типов делать код лаконичным.
Часто задаваемые вопросы
Урок «Обобщения компонентов — введение» бесплатный?
Да — полный текст урока «Обобщения компонентов — введение» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс TypeScript Academy, подпишись на CoddyKit PRO. Курс TypeScript Academy содержит 3 уроков всего.
Чему я научусь в уроке «Обобщения компонентов — введение»?
Создавайте повторно используемые компоненты с параметрами типов , ограничениями и выводом типов; безопасно передавайте типизированные render-пропы и ключи. Ты практикуешь TypeScript Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать TypeScript Academy?
Предыдущий опыт не требуется. TypeScript Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 3.
Сколько времени занимает урок «Обобщения компонентов — введение»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке TypeScript Academy?
Да. Каждый урок TypeScript Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Свойства и дочерние элементы; обработчики событий; ссылки
- Состояние и редьюсеры; типизация Context
- Обобщения компонентов — введение