0Pricing
React Academy · Lección

Componentes genéricos y tipos utilitarios

Escriba componentes genéricos reutilizables y utilice PropsWithChildren, ComponentProps y Omit.

Componentes genéricos y tipos utilitarios 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.

¿Por qué componentes genéricos?

Los componentes genéricos se adaptan a distintos tipos de datos y mantienen la seguridad de tipos: una lista, un selector o una tabla tipados que funcionan con cualquier forma de datos.

Una lista genérica sencilla

Utilice un parámetro de tipo T en la función para crear un componente de lista que renderice elementos de cualquier tipo.

interface ListProps<T> {
  items: T[];
  renderItem: (item: T, index: number) => React.ReactNode;
  keyExtractor: (item: T) => string;
}

function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
  return (
    <ul>
      {items.map((item, i) => (
        <li key={keyExtractor(item)}>{renderItem(item, i)}</li>
      ))}
    </ul>
  );
}

Restringir tipos genéricos

Utilice extends para añadir restricciones, de modo que TypeScript sepa qué propiedades debe tener el tipo.

interface SelectProps<T extends { id: string; label: string }> {
  options: T[];
  value: T | null;
  onChange: (option: T) => void;
}

function Select<T extends { id: string; label: string }>(
  { options, value, onChange }: SelectProps<T>
) {
  return (
    <select value={value?.id} onChange={e => onChange(options.find(o => o.id === e.target.value)!)}>
      {options.map(o => <option key={o.id} value={o.id}>{o.label}</option>)}
    </select>
  );
}

PropsWithChildren

React.PropsWithChildren<P> añade children?: React.ReactNode a cualquier tipo de props, lo que resulta útil para los componentes contenedores.

function Card({ title, children }: React.PropsWithChildren<{ title: string }>) {
  return (
    <div className="card">
      <h2>{title}</h2>
      {children}
    </div>
  );
}

ComponentProps

React.ComponentProps<typeof Component> extrae las props de un componente existente, lo que resulta útil cuando desea extenderlo o envolverlo.

import { Button } from './Button';

type ExtendedButtonProps = React.ComponentProps<typeof Button> & {
  loading?: boolean;
};

function LoadingButton({ loading, children, ...props }: ExtendedButtonProps) {
  return (
    <Button {...props} disabled={loading || props.disabled}>
      {loading ? <Spinner /> : children}
    </Button>
  );
}

ComponentPropsWithoutRef

React.ComponentPropsWithoutRef<'input'> extrae las props de un elemento HTML sin la prop ref, por lo que resulta ideal para envolver elementos HTML.

type InputProps = React.ComponentPropsWithoutRef<'input'> & {
  label: string;
  error?: string;
};

function FormInput({ label, error, ...inputProps }: InputProps) {
  return (
    <div>
      <label>{label}</label>
      <input {...inputProps} />
      {error && <span className="error">{error}</span>}
    </div>
  );
}

Omit y Pick

Utilice Omit<T, Keys> para eliminar props específicas y Pick<T, Keys> para conservar únicamente props específicas de un tipo existente.

interface UserCardProps {
  id: string;
  name: string;
  email: string;
  avatar: string;
  role: string;
}

// Only expose non-sensitive fields:
type PublicUserCardProps = Omit<UserCardProps, 'email' | 'role'>;
// Or pick exactly what you need:
type AvatarProps = Pick<UserCardProps, 'name' | 'avatar'>;

Partial y Required

Partial<T> hace que todas las props sean opcionales, lo que resulta útil para formularios de actualización. Required<T> hace que todas las props sean obligatorias.

interface UserFormData { name: string; email: string; bio: string; }

// For update: only send changed fields
type UserUpdatePayload = Partial<UserFormData>;

// For create: all fields are mandatory
type UserCreatePayload = Required<UserFormData>;

Record para diccionarios tipados

Record<Keys, Value> crea un tipo de objeto con tipos de clave específicos, lo que resulta útil para mapas de búsqueda y traducciones.

type Status = 'idle' | 'loading' | 'success' | 'error';

const statusLabels: Record<Status, string> = {
  idle: 'Ready',
  loading: 'Loading...',
  success: 'Done!',
  error: 'Something went wrong',
};

ReturnType para tipos de hooks

Utilice ReturnType<typeof useMyHook> para inferir el tipo de retorno de un hook personalizado sin duplicarlo manualmente.

function useCounter(initial: number) {
  const [count, setCount] = useState(initial);
  return { count, increment: () => setCount(c => c + 1) };
}

type CounterHook = ReturnType<typeof useCounter>;
// { count: number; increment: () => void }

Componente de tabla genérico

Una tabla de datos completamente segura en cuanto a tipos que funciona con cualquier forma de fila, infiere las claves de las columnas y sigue ofreciendo autocompletado.

interface Column<T> {
  key: keyof T;
  header: string;
  render?: (value: T[keyof T], row: T) => React.ReactNode;
}

function DataTable<T extends object>({ data, columns }: { data: T[]; columns: Column<T>[] }) {
  return (
    <table>
      <thead><tr>{columns.map(c => <th key={String(c.key)}>{c.header}</th>)}</tr></thead>
      <tbody>{data.map((row, i) => (
        <tr key={i}>{columns.map(c => <td key={String(c.key)}>{c.render ? c.render(row[c.key], row) : String(row[c.key])}</td>)}</tr>
      ))}</tbody>
    </table>
  );
}

Comprobación rápida

¿Qué tipo de utilidad elimina claves especificadas de una interfaz existente de TypeScript?

Resumen

Los componentes genéricos utilizan parámetros de tipo para mantener la seguridad de tipos con distintas formas de datos. Los tipos de utilidad, como Omit, Pick, Partial, ComponentProps y PropsWithChildren, eliminan la duplicación manual de tipos y hacen que las API de los componentes sean más componibles.

Preguntas frecuentes

¿La lección «Componentes genéricos y tipos utilitarios» es gratis?

Sí — el texto completo de «Componentes genéricos y tipos utilitarios» 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 genéricos y tipos utilitarios»?

Escriba componentes genéricos reutilizables y utilice PropsWithChildren, ComponentProps y Omit. 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 genéricos y tipos utilitarios»?

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

  1. Tipar props y tipos de retorno de componentes
  2. Tipar eventos y refs en TypeScript
  3. Componentes genéricos y tipos utilitarios
  4. Tipar contextos y custom hooks
← Volver a React Academy