TypeScript de Cero a Experto / Utility types
Partial, Required y Readonly: modificar los campos
El primer grupo de utility types cambia una característica de TODOS los campos de un
tipo a la vez: Partial los hace opcionales, Required los hace obligatorios,
Readonly los hace de solo lectura. Cada uno resuelve un caso concreto que vas a
encontrar en toda app: actualizar, exigir, y proteger.
Los tres interruptores globales
Partial<T>: todos opcionales
El más usado del grupo. Convierte cada campo en opcional —perfecto para funciones de ACTUALIZACIÓN, donde solo mandas los campos que cambian:
type Gasto = {
id: number;
nombre: string;
valor: number;
categoria: string;
};
// Partial<Gasto> = todos los campos opcionales:
// { id?: number; nombre?: string; valor?: number; categoria?: string }
// función de actualización: recibes el original y SOLO los cambios
function actualizar(gasto: Gasto, cambios: Partial<Gasto>): Gasto {
return { ...gasto, ...cambios }; // spread: los cambios pisan lo viejo
}
const cafe: Gasto = { id: 1, nombre: "Café", valor: 4000, categoria: "comida" };
const masCaro = actualizar(cafe, { valor: 4500 }); // solo el valor
const renombrado = actualizar(cafe, { nombre: "Latte", valor: 5000 }); // dos campos
// actualizar(cafe, { precio: 9 }); // ❌ 'precio' no es un campo de GastoPartial<Gasto> te deja pasar cualquier subconjunto de campos —desde uno hasta
todos— y ninguno inventado. Es el tipo natural de un "parche" o "cambios": el patrón
de toda función update, patch o merge. Sin él, tendrías que escribir a mano la
versión con todos los ?, y mantenerla sincronizada.
Required<T>: todos obligatorios
El opuesto: elimina los ? y hace cada campo obligatorio. Útil cuando partes de un
tipo con opcionales y necesitas una versión "completa y verificada":
// una config donde casi todo es opcional (con defaults):
type Config = {
tema?: "claro" | "oscuro";
idioma?: string;
animaciones?: boolean;
};
// tras aplicar los defaults, quieres GARANTIZAR que ya no falta ninguno:
type ConfigCompleta = Required<Config>;
// = { tema: "claro" | "oscuro"; idioma: string; animaciones: boolean } — sin ?
function aplicarDefaults(parcial: Config): ConfigCompleta {
return {
tema: parcial.tema ?? "oscuro",
idioma: parcial.idioma ?? "es",
animaciones: parcial.animaciones ?? true,
};
}
const config = aplicarDefaults({ tema: "claro" });
config.idioma.toUpperCase(); // ✓ TS SABE que idioma existe (no es opcional)Required<Config> garantiza en el TIPO que ya no hay campos ausentes —así, tras
aplicar los defaults, accedes a config.idioma sin chequear si existe. Es el patrón
"entra parcial, sale completo": muy común al normalizar configuraciones y opciones.
Readonly<T>: inmutabilidad garantizada
Convierte todos los campos en readonly: no se pueden reasignar tras crear el
objeto. La inmutabilidad del módulo 12 de JS, ahora VIGILADA por el compilador:
type Usuario = { id: number; nombre: string };
// Readonly<Usuario> = { readonly id: number; readonly nombre: string }
function saludar(u: Readonly<Usuario>): string {
// u.nombre = "otro"; // ❌ Cannot assign to 'nombre' because it is read-only
return "Hola, " + u.nombre; // leer sí, mutar no
}
// perfecto para parámetros: comunica "no voy a modificar esto" y TS lo garantiza.
const sara: Usuario = { id: 1, nombre: "Sara" };
saludar(sara); // dentro, sara está protegido de mutaciones accidentalesEscribes una función editarPerfil(perfil: Usuario, cambios: ???) que aplica solo los campos que el usuario modificó. ¿Qué tipo debe tener 'cambios'?
Mini-reto
Aplica los tres: 1) define type Cuenta = { id: number; saldo: number; activa: boolean }; 2) escribe function transferir(cuenta: Readonly<Cuenta>, cambios: Partial<Cuenta>): Cuenta que devuelva una copia con los cambios (sin mutar la
original —el Readonly te lo garantiza); 3) prueba pasar solo { saldo: 100 } y
confirma que TS acepta el parcial pero rechaza { moneda: "COP" }. Los tres
interruptores, en acción.
Qué sigue
Partial/Required/Readonly modifican TODOS los campos. El siguiente grupo hace
lo contrario: SELECCIONA algunos. Pick se queda con las claves que eliges, Omit
quita las que no quieres —los utility types con los que construyes vistas parciales
de tus datos, como un tipo público que oculta la contraseña.