0Pricing
TypeScript Academy · Leçon

Composants polymorphes ; props as

Construisez un composant Button polymorphe avec une prop as ; fusionnez les props intrinsèques et du DOM ; typez les refs avec forwardRef et ComponentRef .

Composants polymorphes ; props as est une leçon TypeScript Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 1. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage TypeScript Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours TypeScript Academy comprend 1 leçons au total.

Introduction

Objectif : créez un Button polymorphe capable d’être rendu comme button, a ou n’importe quel élément grâce à une propriété as, tout en conservant les types des propriétés et de la référence.

  • Restreignez T à React.ElementType
  • Fusionnez les propriétés en toute sécurité
  • Typez la référence transmise

Types de base

Commencez avec OwnProps et un utilitaire PolymorphicProps<T, P> qui fusionne les propriétés intrinsèques de T avec les vôtres.

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 polymorphe

Le composant utilise button par défaut, mais accepte as. Le type de la référence change avec T (par exemple, HTMLAnchorElement pour "a").

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

Exemples d’utilisation

Avec as="a", les propriétés intrinsèques telles que href deviennent disponibles et la référence est typée comme 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>
  )
}

Variantes

Vous pouvez envelopper le composant polymorphe tout en conservant sa flexibilité. Utilisez ComponentProps<typeof Button> pour hériter de ses propriétés.

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>
  )
}

Conseils

Conseils :

  • Restreignez T à React.ElementType.
  • Utilisez Omit pour résoudre les collisions de noms de propriétés.
  • Transmettez la référence avec forwardRef et typez-la comme React.ComponentRef<T>.

Vérification du typage polymorphe

Vérification rapide : quel typage modélise correctement un composant polymorphe qui transmet sa référence ?

Récapitulatif

Récapitulatif : vous avez créé un Button polymorphe avec une propriété as, fusionné les propriétés intrinsèques en toute sécurité et typé la référence transmise afin que les consommateurs bénéficient d’une autocomplétion correcte.

Questions Fréquemment Posées

La leçon « Composants polymorphes ; props as » est-elle gratuite ?

Oui — le texte complet de « Composants polymorphes ; props as » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours TypeScript Academy, passe à CoddyKit PRO. Le cours TypeScript Academy comprend 1 leçons au total.

Qu'est-ce que j'apprendrai dans « Composants polymorphes ; props as » ?

Construisez un composant Button polymorphe avec une prop as ; fusionnez les props intrinsèques et du DOM ; typez les refs avec forwardRef et ComponentRef . Tu pratiques TypeScript Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer TypeScript Academy ?

Aucune expérience préalable n'est requise. TypeScript Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 1.

Combien de temps prend la leçon « Composants polymorphes ; props as » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon TypeScript Academy ?

Oui. Chaque leçon TypeScript Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

← Retour à TypeScript Academy