← React & TypeScript

React with TypeScript

How do you type a component's props in React with TypeScript?

Show answer — try answering out loud first

I define a type or interface with the shape of the props and apply it directly to the component's parameter. Optional props take ? and I give them a default value when destructuring. React.FC is no longer recommended.

Props are your component's "contract": what data it needs to work. TypeScript lets you write that contract explicitly, and in return it warns you if someone uses the component wrong (missing a prop, passing a string where a number was expected, etc.).

The key points:

  • You define a type (or interface, both work) with the name ComponentNameProps by convention.
  • You apply it to the component's parameter: function Boton({ texto }: BotonProps).
  • Optional props are marked with ?. If you want a default value, you assign it when destructuring: { color = "azul" }.
  • Functions that arrive via props are also typed: onGuardar: (id: number) => void says "you pass me a function that receives a number and returns nothing".
  • React.FC was popular, but today it's not recommended: it used to inject children even if you didn't use it and it complicates generics. Typing the parameter directly is simpler and more explicit.
// The component's contract: what it receives and of what type
type BotonGuardarProps = {
  texto: string;                      // required
  id: number;                         // required
  deshabilitado?: boolean;            // optional (may not be provided)
  color?: "azul" | "rojo";            // optional, with limited values
  onGuardar: (id: number) => void;    // function that receives a number
};

// Default values directly in the destructuring
function BotonGuardar({
  texto,
  id,
  deshabilitado = false,
  color = "azul",
  onGuardar,
}: BotonGuardarProps) {
  return (
    <button
      disabled={deshabilitado}
      className={`boton-${color}`}
      onClick={() => onGuardar(id)}
    >
      {texto}
    </button>
  );
}

// Correct usage
// <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'

A junior often types the component with React.FC out of habit:

// It works, but it's no longer recommended
const Boton: React.FC<BotonProps> = ({ texto }) => {
  return <button>{texto}</button>;
};

The problem: in older versions React.FC added implicit children (you accepted children without wanting to) and today it still gets in the way with generic components. The fix is to type the parameter directly:

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

Same result, less magic, clearer.

"I type props with a type or interface that I apply directly to the component's parameter, not with React.FC, because that approach injected implicit children and complicates generics. I mark optional props with ? and give them a default value when destructuring. When a prop is a function, I type it too, for example onGuardar: (id: number) => void, so TypeScript warns me if someone uses the component wrong."

Quick challenge

Create a Saludo component that receives nombre (string, required) and formal (boolean, optional, default false). If formal is true, it shows "Buenos días, {nombre}"; otherwise, "Hola, {nombre}".

See solution
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