Fácil TypeScript

Tornar todas as propriedades readonly

Enunciado

Crie um mapped type ReadonlyAll<T> que transforme todas as propriedades de T em readonly. Use a sintaxe [K in keyof T] e o modificador readonly.

Requisitos

  • O tipo deve se chamar ReadonlyAll e aceitar um parâmetro genérico T.
  • Todas as propriedades do tipo resultante devem ser readonly.
  • O tipo deve preservar os tipos originais das propriedades.

Código inicial

type ReadonlyAll<T> = /* complete aqui */;

// Teste:
interface Pessoa {
  nome: string;
  idade: number;
}

const p: ReadonlyAll<Pessoa> = { nome: "Ana", idade: 30 };
// p.nome = "Bia"; // deve dar erro
Ver dica

Use readonly [K in keyof T]: T[K].

Mostrar solução
type ReadonlyAll<T> = {
  readonly [K in keyof T]: T[K];
};

// Teste:
interface Pessoa {
  nome: string;
  idade: number;
}

const p: ReadonlyAll<Pessoa> = { nome: "Ana", idade: 30 };
// p.nome = "Bia"; // Erro: Cannot assign to 'nome' because it is a read-only property.

Passo a passo

  1. Definimos um tipo genérico ReadonlyAll<T> que recebe um parâmetro T.
  2. Usamos a sintaxe de mapped type { [K in keyof T]: T[K] } para iterar sobre as chaves de T.
  3. Adicionamos o modificador readonly antes dos colchetes para tornar cada propriedade somente leitura.
  4. O tipo resultante tem as mesmas chaves de T, mas todas com readonly.
  5. No teste, criamos um objeto p do tipo ReadonlyAll<Pessoa>.
  6. Tentar atribuir a p.nome gera erro de compilação, confirmando que o tipo funciona.

Por que funciona

O mapped type { readonly [K in keyof T]: T[K] } percorre cada chave K de T e cria uma propriedade readonly com o tipo T[K]. O modificador readonly é aplicado a todas as propriedades, impedindo atribuições posteriores. Isso é exatamente o que o tipo utilitário Readonly<T> faz internamente.

Erros comuns

  • Esquecer o readonly antes dos colchetes: { [K in keyof T]: T[K] } não torna as propriedades readonly.
  • Usar keyof T sem o in: { [K keyof T]: T[K] } é sintaxe inválida.
  • Não usar T[K] como tipo do valor: { readonly [K in keyof T]: any } perde a tipagem original.

Outra forma de resolver

Usar o tipo utilitário embutido Readonly<T>:

type ReadonlyAll<T> = Readonly<T>;

É preferível quando você não precisa de customizações adicionais.

Saída esperada

Não há saída em tempo de execução, pois o código apenas demonstra tipagem estática. O erro de compilação ao tentar modificar p.nome é o resultado esperado.