0Pricing
TypeScript Academy · Урок

Полиморфные компоненты; свойства 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 — локальная установка не требуется.

← Назад к TypeScript Academy