Componentes polimórficos con la prop 'as'
Tipifique la prop 'as' para que un Button se renderice como o conservando los tipos de props correctos.
Componentes polimórficos con la prop 'as' es una lección gratuita de React Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de React Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de React Academy incluye 4 lecciones en total.
¿Qué es un componente polimórfico?
Un componente polimórfico se renderiza como distintos elementos HTML o componentes según una prop as; por ejemplo, un Button que se renderiza como <a> o <button> y mantiene los tipos correctos de TypeScript.
Prop as sencilla (sin TypeScript)
Una implementación polimórfica básica sin genéricos: pierde la seguridad de tipos, pero muestra el concepto.
function Box({ as: Tag = 'div', children, ...props }) {
return <Tag {...props}>{children}</Tag>;
}
// Usage:
<Box as="section" className="hero">...</Box>
<Box as="article">...</Box>Prop as tipada con genéricos
Añada un parámetro de tipo genérico para inferir las props correctas del elemento que se renderice mediante as.
type PolymorphicProps<E extends React.ElementType> = {
as?: E;
} & Omit<React.ComponentPropsWithoutRef<E>, 'as'>;
function Box<E extends React.ElementType = 'div'>({
as,
...props
}: PolymorphicProps<E>) {
const Tag = as ?? 'div';
return <Tag {...props} />;
}Compatibilidad con ref
Añada compatibilidad con forwardRef y conserve el tipado polimórfico.
type PolymorphicRef<E extends React.ElementType> = React.ComponentPropsWithRef<E>['ref'];
type PolymorphicPropsWithRef<E extends React.ElementType, P = {}> = P &
Omit<React.ComponentPropsWithRef<E>, keyof P> & { as?: E };
const Button = React.forwardRef(
<E extends React.ElementType = 'button'>(
{ as, ...props }: PolymorphicPropsWithRef<E>,
ref: PolymorphicRef<E>
) => {
const Tag = as ?? 'button';
return <Tag ref={ref} {...props} />;
}
);Inferencia de TypeScript en acción
Cuando establece as='a', TypeScript sabe que el componente acepta props específicas de los enlaces, como href y target, pero no props específicas de los botones, como disabled.
// TypeScript allows href because as='a':
<Box as="a" href="https://example.com">Link</Box>
// TypeScript errors if you pass href to a div:
<Box as="div" href="...">Error!</Box> // TS: href is not a valid div propExtensión con props personalizadas
Añada props específicas del componente junto a la base polimórfica incluyéndolas en la definición del tipo.
type TextProps<E extends React.ElementType> = PolymorphicProps<E> & {
size?: 'sm' | 'md' | 'lg';
weight?: 'normal' | 'bold';
};
function Text<E extends React.ElementType = 'p'>({
as,
size = 'md',
weight = 'normal',
className,
...props
}: TextProps<E>) {
const Tag = as ?? 'p';
return (
<Tag
className={[`text-${size}`, `font-${weight}`, className].filter(Boolean).join(' ')}
{...props}
/>
);
}Caso de uso real: Link que se renderiza como RouterLink
Un Button que se renderiza como el Link de React Router cuando se proporciona to o como un botón normal en caso contrario.
import { Link } from 'react-router-dom';
type ButtonProps =
| { to: string; href?: never } & React.ComponentPropsWithoutRef<typeof Link>
| { href: string; to?: never } & React.ComponentPropsWithoutRef<'a'>
| { to?: never; href?: never } & React.ComponentPropsWithoutRef<'button'>;
function Button({ to, href, ...props }: ButtonProps) {
if (to) return <Link to={to} {...props} />;
if (href) return <a href={href} {...props} />;
return <button type="button" {...props} />;
}Componente Text de un sistema de diseño
Un componente polimórfico Text que usa <p> de forma predeterminada, pero puede renderizarse como h1–h6, span o label.
<Text as="h1" size="xl">Page Title</Text>
<Text as="span" weight="bold">Inline bold</Text>
<Text as="label" htmlFor="email">Email</Text> // htmlFor is valid because as='label'Restricciones de la prop as
Use extends React.ElementType para aceptar tanto cadenas de elementos HTML ('div', 'a') como componentes de React.
function Card<E extends React.ElementType = 'div'>({ as, ...props }: PolymorphicProps<E>) {
const Tag = as ?? 'div';
return <Tag {...props} />;
}
// Works with HTML elements:
<Card as="section" aria-label="Products" />
// Works with React components:
<Card as={motion.div} animate={{ opacity: 1 }} />Evitar errores habituales
No incluya la prop as al propagarla al elemento, ya que no es un atributo HTML válido. Desestructúrela siempre antes de propagar el resto de las props.
// Bad:
function Box({ as: Tag = 'div', ...props }) {
return <Tag as={...} {...props} />; // 'as' attribute on div is invalid HTML
}
// Good:
function Box({ as: Tag = 'div', ...props }) {
return <Tag {...props} />; // 'as' is used to pick Tag, not passed to element
}Consideración de rendimiento
Los componentes polimórficos tienen un coste de rendimiento mínimo: la prop as es simplemente una variable que contiene una cadena con el tipo de elemento o una referencia a un componente.
Comprobación rápida
¿Por qué debe desestructurar la prop as antes de propagar el resto de las props al elemento en un componente polimórfico?
Resumen
Los componentes polimórficos usan una prop genérica as?: E extends React.ElementType para renderizar cualquier elemento y conservar las props correctas de TypeScript. Desestructure as antes de propagar el resto de las props. Use React.ComponentPropsWithoutRef para incluir en el tipo todos los atributos específicos del elemento.
Preguntas frecuentes
¿La lección «Componentes polimórficos con la prop 'as'» es gratis?
Sí — el texto completo de «Componentes polimórficos con la prop 'as'» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de React Academy, actualiza a CoddyKit PRO. El curso de React Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Componentes polimórficos con la prop 'as'»?
Tipifique la prop 'as' para que un Button se renderice como o conservando los tipos de props correctos. Practicas React Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar React Academy?
No se requiere experiencia previa. React Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Componentes polimórficos con la prop 'as'»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de React Academy?
Sí. Cada lección de React Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Uniones discriminadas para variantes de componentes
- Tipos condicionales y mapeados en React
- Componentes polimórficos con la prop 'as'
- Formularios con seguridad de tipos y contratos de respuestas de API