Padrões de Imutabilidade Profunda
Obtenha estruturas profundamente somente para leitura com tipos recursivos.
Padrões de Imutabilidade Profunda é uma aula grátis de TypeScript Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de TypeScript Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de TypeScript Academy inclui 4 aulas no total.
Imutabilidade superficial vs profunda
O modificador readonly é superficial: ele protege o nível superior, mas não os objetos aninhados. Imutabilidade profunda significa que todos os níveis, até o mais interno, são somente leitura. Alcançá-la exige trabalho 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 que a imutabilidade superficial não basta
Para o gerenciamento de state e de dados compartilhados, a característica somente leitura superficial deixa os campos aninhados expostos. Uma única alteração despercebida no interior de uma estrutura pode causar erros sutis e difíceis 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);Um tipo DeepReadonly recursivo
Podemos criar um tipo mapeado que aplica readonly recursivamente. DeepReadonly<T> percorre cada propriedade e, se ela for um objeto, aplica recursão a ele.
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object
? DeepReadonly<T[K]>
: T[K];
};
console.log('DeepReadonly defined');Aplicando DeepReadonly
Envolver um tipo com DeepReadonly também torna imutáveis as propriedades aninhadas. Agora, nem mesmo s.user.name pode receber uma nova atribuição — a proteção alcança todos os níveis.
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);Como funciona o tipo mapeado
O [K in keyof T] percorre cada chave. O prefixo readonly bloqueia cada uma delas. A expressão condicional T[K] extends object ? ... : T[K] decide se deve aplicar recursão ou parar em um 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);Proteção apenas em tempo de compilação
DeepReadonly impõe a imutabilidade no sistema de tipos, não em tempo de execução. O objeto JavaScript ainda é tecnicamente mutável por meio de caminhos sem tipagem — mas o código com tipagem fica totalmente 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');Congelando objetos aninhados em tempo de execução
Para obter imutabilidade real em tempo de execução, use Object.freeze. Ele impede adicionar, remover ou alterar propriedades — mas, assim como readonly, é superficial por padrão.
const config = Object.freeze({ host: 'localhost', port: 8080 });
console.log(config.port);
// In strict mode, config.port = 1 throws; otherwise silently ignored.Um auxiliar de congelamento profundo
Para congelar profundamente em tempo de execução, percorra os objetos aninhados recursivamente e congele cada um deles. Isso combina naturalmente com o DeepReadonly no nível dos tipos, proporcionando imutabilidade de ponta a ponta.
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);Imutabilidade para um state mais seguro
A imutabilidade profunda é a base de um state previsível. Quando os dados não podem ser alterados no próprio lugar, as atualizações precisam criar novos objetos, tornando as alterações explícitas e fáceis de acompanhar.
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);Padrão de atualização imutável
Com dados somente leitura, você produz novas versões usando o operador de espalhamento. Cada atualização é um novo objeto, portanto os estados anteriores permanecem intactos — algo valioso para desfazer ações, depuração com viagem no tempo e detecção de alterações.
type State = { readonly items: readonly string[] };
const s: State = { items: ['a'] };
const updated: State = { items: [...s.items, 'b'] };
console.log(s.items, updated.items);Combinando segurança de tipos e de execução
A abordagem mais robusta usa os dois recursos: DeepReadonly para garantias em tempo de compilação e deepFreeze para imposição em tempo de execução. Juntos, eles tornam as alterações acidentais quase impossíveis.
function freeze<T>(obj: T): T {
return Object.freeze(obj);
}
const settings = freeze({ theme: 'dark', version: 2 });
console.log(settings.theme, settings.version);Verificação rápida
Teste sua compreensão da imutabilidade profunda.
Recapitulação: imutabilidade profunda
Você aprendeu que:
readonlyé superficial; os campos aninhados continuam mutáveis.- Um tipo mapeado recursivo
DeepReadonly<T>aplica somente leitura em todos os níveis. - Ele existe apenas em tempo de compilação; use
Object.freeze(de forma profunda) para impor a imutabilidade em tempo de execução. - A imutabilidade permite um state seguro e previsível por meio de padrões de cópia durante as atualizações.
Isso conclui a trilha da Academia TypeScript sobre tipos avançados e imutabilidade.
type State = { readonly value: number };
const s: State = { value: 1 };
const next: State = { ...s, value: s.value + 1 };
console.log(s.value, next.value);Perguntas Frequentes
A aula “Padrões de Imutabilidade Profunda” é grátis?
Sim — o texto completo de “Padrões de Imutabilidade Profunda” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de TypeScript Academy, atualize para CoddyKit PRO. O curso de TypeScript Academy inclui 4 aulas no total.
O que vou aprender em “Padrões de Imutabilidade Profunda”?
Obtenha estruturas profundamente somente para leitura com tipos recursivos. Você pratica TypeScript Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar TypeScript Academy?
Nenhuma experiência prévia é necessária. TypeScript Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.
Quanto tempo leva a aula “Padrões de Imutabilidade Profunda”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de TypeScript Academy?
Sim. Cada aula de TypeScript Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Propriedades readonly
- Matrizes e Tuplas readonly
- ReadonlyArray e ReadonlyMap
- Padrões de Imutabilidade Profunda