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>.