CodeForge

TypeScript de Cero a Experto / Utility types

Utility types: transformadores de tipos ya hechos

Teoría20 min20 XP

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:

el-problema.ts
// 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:

la-solucion.ts
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.