0Pricing
TypeScript Academy · Aula

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

  1. Propriedades readonly
  2. Matrizes e Tuplas readonly
  3. ReadonlyArray e ReadonlyMap
  4. Padrões de Imutabilidade Profunda
← Voltar para TypeScript Academy