TypeScript de Cero a Experto / Utility types
Utility types: transformadores de tipos ya hechos
Ahora que entiendes los genéricos, TypeScript te entrega un regalo enorme: docenas
de "utility types" —transformadores que toman un tipo y devuelven otro derivado—.
¿Necesitas una versión de tu tipo con todos los campos opcionales? ¿Sin el id?
¿Solo con dos propiedades? No lo reescribas: DERÍVALO. Es el principio DRY (no te
repitas) aplicado a los tipos.
Las lentes que transforman
El problema: tipos que se repiten
Sin utility types, terminas escribiendo variantes del mismo tipo a mano —y manteniéndolas sincronizadas a pulso:
// tu tipo base
type Gasto = {
id: number;
nombre: string;
valor: number;
categoria: string;
};
// ❌ para CREAR un gasto (aún sin id), reescribes casi todo:
type GastoNuevo = {
nombre: string;
valor: number;
categoria: string;
};
// ❌ para ACTUALIZAR (todos los campos opcionales), reescribes otra vez:
type GastoCambios = {
nombre?: string;
valor?: number;
categoria?: string;
};
// el día que agregas 'nota' a Gasto, tienes que acordarte de tocar
// GastoNuevo y GastoCambios también. Tres lugares, siempre desincronizándose.Eso es duplicación pura: tres tipos que describen el mismo dato con pequeñas
variaciones, y que hay que mantener a mano. Agregas un campo a Gasto y debes
recordar tocar los otros dos —o se desincronizan y aparecen bugs. Los utility types
matan ese problema de raíz.
La solución: derivar con utility types
Los mismos tres tipos, DERIVADOS del original con una línea cada uno:
type Gasto = {
id: number;
nombre: string;
valor: number;
categoria: string;
};
// ✅ para crear: Gasto SIN el campo id
type GastoNuevo = Omit<Gasto, "id">;
// = { nombre: string; valor: number; categoria: string }
// ✅ para actualizar: Gasto con TODOS los campos opcionales
type GastoCambios = Partial<Gasto>;
// = { id?: number; nombre?: string; valor?: number; categoria?: string }
// ahora, si agregas 'nota' a Gasto, GastoNuevo y GastoCambios
// se actualizan SOLOS. Una fuente de verdad, cero desincronización.Omit<Gasto, "id"> y Partial<Gasto> derivan de Gasto automáticamente: cambia el
original y las derivadas lo siguen. Esto no es un truco menor —es cómo se mantienen
sanas las bases de código grandes: los tipos relacionados se DERIVAN unos de otros,
nunca se copian.
El mapa del módulo
Tienes type Usuario con 8 campos y necesitas un tipo 'UsuarioParaCrear' idéntico pero sin el campo 'id'. ¿Cuál es el mejor enfoque?
Mini-reto
Deriva en vez de repetir: 1) define type Articulo = { id: number; titulo: string; cuerpo: string; publicado: boolean }; 2) crea type ArticuloBorrador = Omit<Articulo, "id" | "publicado"> (para redactar antes de publicar) y type ArticuloParche = Partial<Articulo> (para ediciones); 3) confirma en tu editor que ambos derivan sus
campos de Articulo. Sientes el DRY aplicado a los tipos.
Qué sigue
Ya viste el poder de derivar. La próxima lección toma el primer grupo a fondo:
Partial, Required y Readonly —los que MODIFICAN los campos de un tipo—, con
los casos reales donde cada uno te salva: actualizaciones, configuraciones e
inmutabilidad garantizada.