DevPath · Aprende a programar ESPTEN

Node con TypeScript

Tipar una API Express

Tipos para los datos: los DTO

Un DTO (Data Transfer Object) describe la forma de los datos que entran y salen de tu API. Lo modelas con una interface o un type:

// Lo que el cliente envía para crear un usuario (cuerpo de la petición)
interface CrearUsuarioDTO {
  nombre: string;
  email: string;
  edad?: number;        // opcional
}

// Lo que la API devuelve
interface UsuarioRespuesta {
  id: number;
  nombre: string;
  email: string;
}

interface y type son casi intercambiables para describir objetos. Una diferencia práctica: type también nombra uniones y primitivos (type Id = number | string), mientras que interface se centra en la forma de objetos y se puede extender.

Tipar req y res

Express expone tipos genéricos Request y Response. Los parámetros de la firma te dejan tipar req.params, el cuerpo y la respuesta:

import { Request, Response } from "express";

// Request<Params, ResBody, ReqBody>
app.post(
  "/usuarios",
  (req: Request<{}, UsuarioRespuesta, CrearUsuarioDTO>, res: Response<UsuarioRespuesta>) => {
    const { nombre, email } = req.body;   // req.body: CrearUsuarioDTO
    const usuario = { id: 1, nombre, email };
    res.status(201).json(usuario);        // res.json espera UsuarioRespuesta
  }
);

Ahora el editor te autocompleta req.body.nombre y te marca un error si intentas res.json({ foo: 1 }), porque no encaja con UsuarioRespuesta.

Los parámetros de ruta se tipan igual:

app.get("/usuarios/:id", (req: Request<{ id: string }>, res: Response) => {
  const id = req.params.id;   // string (los params SIEMPRE llegan como string)
  res.json({ id });
});

Genéricos básicos

Un genérico es un tipo con un "hueco" que se rellena al usarlo: te permite escribir una pieza reutilizable sin perder la información de tipos.

interface ApiResponse<T> {
  ok: boolean;
  data: T;
}

const r1: ApiResponse<UsuarioRespuesta> = { ok: true, data: { id: 1, nombre: "Ada", email: "a@x.com" } };
const r2: ApiResponse<number[]>         = { ok: true, data: [1, 2, 3] };

ApiResponse<T> es la misma envoltura para cualquier data: el <T> conserva el tipo concreto en cada uso. Es exactamente lo que hace Express con Request<Params, ResBody, ReqBody>.

Pon esto en práctica

DevPath es un curso práctico: aquí lees la teoría; en la app la pones en práctica con ejercicios que se ejecutan de verdad, sin conexión.

Empezar gratis en la app →
← Por qué TypeScript en el backendTipos útiles y la frontera runtime →