← React & TypeScript

React con TypeScript

¿Cómo tipas las props de un componente en React con TypeScript?

Ver respuesta — intenta responderla en voz alta primero

Defino un type o interface con la forma de las props y lo aplico directo al parámetro del componente. Las props opcionales llevan ? y les doy un valor por defecto al destructurar. Ya no se recomienda React.FC.

Las props son el "contrato" de tu componente: qué datos necesita para funcionar. TypeScript te permite escribir ese contrato de forma explícita, y a cambio te avisa si alguien usa el componente mal (le falta una prop, le pasa un string donde iba un number, etc.).

Los puntos clave:

  • Defines un type (o interface, ambos funcionan) con el nombre NombreDelComponenteProps por convención.
  • Lo aplicas al parámetro del componente: function Boton({ texto }: BotonProps).
  • Las props opcionales se marcan con ?. Si quieres un valor por defecto, lo asignas al destructurar: { color = "azul" }.
  • Las funciones que llegan por props también se tipan: onGuardar: (id: number) => void dice "me pasas una función que recibe un número y no devuelve nada".
  • React.FC fue popular, pero hoy no se recomienda: antes inyectaba children aunque no lo usaras y complica los genéricos. Tipar el parámetro directo es más simple y explícito.
// El contrato del componente: qué recibe y de qué tipo
type BotonGuardarProps = {
  texto: string;                      // obligatoria
  id: number;                         // obligatoria
  deshabilitado?: boolean;            // opcional (puede no venir)
  color?: "azul" | "rojo";            // opcional, con valores limitados
  onGuardar: (id: number) => void;    // función que recibe un número
};

// Valores por defecto directo en el destructuring
function BotonGuardar({
  texto,
  id,
  deshabilitado = false,
  color = "azul",
  onGuardar,
}: BotonGuardarProps) {
  return (
    <button
      disabled={deshabilitado}
      className={`boton-${color}`}
      onClick={() => onGuardar(id)}
    >
      {texto}
    </button>
  );
}

// Uso correcto
// <BotonGuardar texto="Guardar" id={7} onGuardar={(id) => console.log(id)} />

// <BotonGuardar texto="Guardar" onGuardar={...} />
// Error: Property 'id' is missing in type ...

// <BotonGuardar texto="Guardar" id="7" onGuardar={...} />
// Error: Type 'string' is not assignable to type 'number'

Un junior suele tipar el componente con React.FC por costumbre:

// Funciona, pero ya no se recomienda
const Boton: React.FC<BotonProps> = ({ texto }) => {
  return <button>{texto}</button>;
};

El problema: en versiones antiguas React.FC metía children implícito (aceptabas hijos sin quererlo) y hoy sigue estorbando con componentes genéricos. La corrección es tipar el parámetro directamente:

function Boton({ texto }: BotonProps) {
  return <button>{texto}</button>;
}

Mismo resultado, menos magia, más claro.

"Yo tipo las props con un type o interface que aplico directo al parámetro del componente, no con React.FC, porque ese enfoque inyectaba children implícito y complica los genéricos. Las props opcionales las marco con ? y les doy valor por defecto al destructurar. Cuando una prop es una función, también la tipo, por ejemplo onGuardar: (id: number) => void, y así TypeScript me avisa si alguien usa mal el componente."

Reto rápido

Crea un componente Saludo que reciba nombre (string, obligatorio) y formal (boolean, opcional, por defecto false). Si formal es true, muestra "Buenos días, {nombre}"; si no, "Hola, {nombre}".

Ver solución
type SaludoProps = {
  nombre: string;
  formal?: boolean;
};

function Saludo({ nombre, formal = false }: SaludoProps) {
  const mensaje = formal ? `Buenos días, ${nombre}` : `Hola, ${nombre}`;
  return <p>{mensaje}</p>;
}

// <Saludo nombre="Ana" />            -> Hola, Ana
// <Saludo nombre="Ana" formal />     -> Buenos días, Ana