Patrones de inmutabilidad profunda
Consiga estructuras profundamente readonly mediante tipos recursivos.
Patrones de inmutabilidad profunda es una lección gratuita de TypeScript Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de TypeScript Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de TypeScript Academy incluye 4 lecciones en total.
Inmutabilidad superficial frente a profunda
El modificador readonly es superficial: protege el nivel superior, pero no los objetos anidados. La inmutabilidad profunda significa que todos los niveles, hasta el último, son readonly. Lograrla requiere trabajo adicional.
interface State { readonly user: { name: string }; }
const s: State = { user: { name: 'Ada' } };
// s.user = {...}; // Error (shallow protection)
s.user.name = 'Grace'; // allowed! nested field is mutable
console.log(s.user.name);Por qué lo superficial no basta
En la gestión de estado y los datos compartidos, el readonly superficial deja expuestos los campos anidados. Una sola mutación pasada por alto en lo profundo de una estructura puede causar errores sutiles y difíciles de rastrear.
interface Config { readonly db: { host: string; port: number }; }
const c: Config = { db: { host: 'localhost', port: 5432 } };
c.db.port = 9999; // mutates nested data despite readonly
console.log(c.db.port);Un tipo DeepReadonly recursivo
Podemos crear un tipo mapeado que aplique readonly de forma recursiva. DeepReadonly<T> recorre cada propiedad y, si es un objeto, se adentra recursivamente en él.
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object
? DeepReadonly<T[K]>
: T[K];
};
console.log('DeepReadonly defined');Aplicar DeepReadonly
Envolver un tipo en DeepReadonly también hace inmutables las propiedades anidadas. Ahora ni siquiera s.user.name se puede reasignar: la protección llega hasta el último nivel.
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object
? DeepReadonly<T[K]>
: T[K];
};
type State = DeepReadonly<{ user: { name: string } }>;
const s: State = { user: { name: 'Ada' } };
// s.user.name = 'x'; // Error now
console.log(s.user.name);Cómo funciona el tipo mapeado
[K in keyof T] itera sobre cada clave. El prefijo readonly bloquea cada una. La condicional T[K] extends object ? ... : T[K] decide si se debe continuar de forma recursiva o detenerse en un tipo primitivo.
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object
? DeepReadonly<T[K]>
: T[K];
};
type Cfg = DeepReadonly<{ a: number; b: { c: string } }>;
const cfg: Cfg = { a: 1, b: { c: 'x' } };
console.log(cfg.a, cfg.b.c);Protección solo en tiempo de compilación
DeepReadonly aplica la inmutabilidad en el sistema de tipos, no en tiempo de ejecución. El objeto JavaScript sigue siendo técnicamente mutable mediante rutas sin tipos, pero el código tipado queda completamente protegido.
// Type-level immutability does not freeze the runtime object.
// For runtime guarantees, combine it with Object.freeze.
console.log('Types guard your code; freeze guards runtime');Congelar objetos anidados en tiempo de ejecución
Para obtener inmutabilidad real en tiempo de ejecución, use Object.freeze. Impide agregar, eliminar o cambiar propiedades, pero, al igual que readonly, es superficial de forma predeterminada.
const config = Object.freeze({ host: 'localhost', port: 8080 });
console.log(config.port);
// In strict mode, config.port = 1 throws; otherwise silently ignored.Una función auxiliar de congelación profunda
Para congelar profundamente en tiempo de ejecución, recorra los objetos anidados y congele cada uno. Esto se combina de forma natural con DeepReadonly en el nivel de tipos para lograr una inmutabilidad integral.
function deepFreeze<T>(obj: T): T {
Object.values(obj as any).forEach((v) => {
if (v && typeof v === 'object') deepFreeze(v);
});
return Object.freeze(obj);
}
const frozen = deepFreeze({ a: { b: 1 } });
console.log(frozen.a.b);Inmutabilidad para un estado más seguro
La inmutabilidad profunda es la base de un estado predecible. Cuando los datos no se pueden mutar in situ, las actualizaciones deben crear objetos nuevos, lo que hace que los cambios sean explícitos y fáciles de seguir.
const state = { count: 0, user: { name: 'Ada' } };
// Immutable update: create a new object instead of mutating
const next = { ...state, count: state.count + 1 };
console.log(state.count, next.count);Patrón de actualizaciones inmutables
Con datos readonly, cree nuevas versiones mediante la sintaxis de propagación. Cada actualización es un objeto nuevo, por lo que los estados anteriores permanecen intactos, algo muy valioso para deshacer acciones, la depuración con viajes en el tiempo y la detección de cambios.
type State = { readonly items: readonly string[] };
const s: State = { items: ['a'] };
const updated: State = { items: [...s.items, 'b'] };
console.log(s.items, updated.items);Combinar seguridad de tipos y de ejecución
La estrategia más sólida utiliza ambas: DeepReadonly para las garantías en tiempo de compilación y deepFreeze para hacerlas cumplir en tiempo de ejecución. Juntas hacen casi imposible la mutación accidental.
function freeze<T>(obj: T): T {
return Object.freeze(obj);
}
const settings = freeze({ theme: 'dark', version: 2 });
console.log(settings.theme, settings.version);Comprobación rápida
Compruebe su comprensión de la inmutabilidad profunda.
Repaso: inmutabilidad profunda
Ha aprendido que:
readonlyes superficial; los campos anidados siguen siendo mutables.- Un tipo mapeado recursivo
DeepReadonly<T>aplica readonly en todos los niveles. - Solo funciona en tiempo de compilación; use
Object.freeze(de forma profunda) para aplicar la inmutabilidad en tiempo de ejecución. - La inmutabilidad permite mantener un estado seguro y predecible mediante patrones de copia al actualizar.
Con esto se completa el itinerario de TypeScript Academy sobre tipos avanzados e inmutabilidad.
type State = { readonly value: number };
const s: State = { value: 1 };
const next: State = { ...s, value: s.value + 1 };
console.log(s.value, next.value);Preguntas frecuentes
¿La lección «Patrones de inmutabilidad profunda» es gratis?
Sí — el texto completo de «Patrones de inmutabilidad profunda» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de TypeScript Academy, actualiza a CoddyKit PRO. El curso de TypeScript Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Patrones de inmutabilidad profunda»?
Consiga estructuras profundamente readonly mediante tipos recursivos. Practicas TypeScript Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar TypeScript Academy?
No se requiere experiencia previa. TypeScript Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Patrones de inmutabilidad profunda»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de TypeScript Academy?
Sí. Cada lección de TypeScript Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Propiedades readonly
- Arrays y tuplas readonly
- ReadonlyArray y ReadonlyMap
- Patrones de inmutabilidad profunda