Полиморфные компоненты; свойства as
Создайте полиморфный компонент Button со свойством as; объедините встроенные свойства и свойства DOM; типизируйте ссылки с помощью forwardRef и ComponentRef .
«Полиморфные компоненты; свойства as» — бесплатный урок TypeScript Academy на CoddyKit. Это урок 1 из 1. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения TypeScript Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс TypeScript Academy содержит 1 уроков всего.
Введение
Цель: создать одну полиморфную Button, которая может отображаться как button, a или любой другой элемент через свойство выбора элемента, сохраняя типы свойств и ссылок.
- Ограничить
TтипомReact.ElementType - Безопасно объединять свойства
- Типизировать перенаправляемую ссылку
Базовые типы
Начните с OwnProps и вспомогательного типа PolymorphicProps<T, P>, который объединяет встроенные свойства для T с вашими собственными.
import React from "react"
type OwnProps = {
variant?: "solid" | "outline"
children: React.ReactNode
}
type PolymorphicProps<T extends React.ElementType, P> = {
as?: T
} & P & Omit<React.ComponentPropsWithoutRef<T>, keyof P | "as">
// Example: Omit avoids prop collisions (e.g., our OwnProps vs intrinsic props)Полиморфная кнопка
Компонент по умолчанию использует button, но принимает свойство выбора элемента. Тип ссылки меняется вместе с T (например, для "a" это тип элемента HTML-якоря).
import React, { forwardRef } from "react"
type OwnProps = { variant?: "solid" | "outline"; children: React.ReactNode }
type PolymorphicProps<T extends React.ElementType, P> = { as?: T } & P & Omit<React.ComponentPropsWithoutRef<T>, keyof P | "as">
const ButtonInner = <T extends React.ElementType = "button">(
{ as, variant = "solid", children, ...rest }: PolymorphicProps<T, OwnProps>,
ref: React.ForwardedRef<React.ComponentRef<T>>
) => {
const Component = (as || "button") as React.ElementType
const style = variant === "outline" ? { border: "1px solid #333", padding: 8 } : { background: "#2563eb", color: "white", padding: 8, borderRadius: 6 }
return <Component ref={ref} style={style} {...rest}>{children}</Component>
}
export const Button = forwardRef(ButtonInner) as <T extends React.ElementType = "button">(
props: PolymorphicProps<T, OwnProps> & { ref?: React.Ref<React.ComponentRef<T>> }
) => JSX.ElementПримеры использования
При as="a" становятся доступны встроенные свойства, например href, а ссылка получает тип HTMLAnchorElement.
import React, { useRef } from "react"
import { Button } from "./Button"
export default function App() {
const btnRef = useRef<HTMLButtonElement>(null)
const linkRef = useRef<HTMLAnchorElement>(null)
return (
<div style={{ display: "grid", gap: 8 }}>
<Button ref={btnRef} onClick={() => alert("clicked")}>Save</Button>
<Button as="a" ref={linkRef} href="#docs" variant="outline">Docs</Button>
</div>
)
}Варианты
Можно обернуть полиморфный компонент и сохранить его гибкость. Используйте ComponentProps<typeof Button>, чтобы унаследовать его свойства.
import React from "react"
import { Button } from "./Button"
export function DangerButton(props: Omit<React.ComponentProps<typeof Button>, "variant">) {
return <Button {...props} style={{ background: "#dc2626", color: "white", padding: 8, borderRadius: 6 }} />
}
// Works with polymorphism too
export default function App() {
return (
<div style={{ display: "grid", gap: 8 }}>
<DangerButton>Delete</DangerButton>
<DangerButton as="a" href="#confirm">Delete link</DangerButton>
</div>
)
}Советы
Советы:
- Ограничивайте
TтипомReact.ElementType. - Используйте
Omitдля устранения конфликтов имён свойств. - Перенаправляйте ссылку с помощью
forwardRefи типизируйте её какReact.ComponentRef<T>.
Проверка полиморфной типизации
Быстрая проверка: какая типизация правильно моделирует полиморфный компонент, перенаправляющий свою ссылку?
Повторение
Повторение: вы создали полиморфную Button со свойством as, безопасно объединили встроенные свойства и типизировали перенаправляемую ссылку, чтобы потребители получали корректное автодополнение.
Часто задаваемые вопросы
Урок «Полиморфные компоненты; свойства as» бесплатный?
Да — полный текст урока «Полиморфные компоненты; свойства as» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс TypeScript Academy, подпишись на CoddyKit PRO. Курс TypeScript Academy содержит 1 уроков всего.
Чему я научусь в уроке «Полиморфные компоненты; свойства as»?
Создайте полиморфный компонент Button со свойством as; объедините встроенные свойства и свойства DOM; типизируйте ссылки с помощью forwardRef и ComponentRef . Ты практикуешь TypeScript Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать TypeScript Academy?
Предыдущий опыт не требуется. TypeScript Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 1.
Сколько времени занимает урок «Полиморфные компоненты; свойства as»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке TypeScript Academy?
Да. Каждый урок TypeScript Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.