CodeForge

TypeScript de Cero a Experto / Utility types

Partial, Required y Readonly: modificar los campos

Teoría20 min20 XP

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:

partial.ts
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 Gasto

Partial<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":

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

readonly.ts
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 accidentales

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