Desafio TypeScript

Remapeamento com as: criar setters tipados

Enunciado

Crie um mapped type Setters<T> que transforme cada propriedade K de T em um método setK que aceita um valor do tipo T[K] e retorna void. Use remapeamento com as e template literals. O nome do método deve ser set seguido da chave capitalizada.

Requisitos

  • O tipo deve se chamar Setters e aceitar um parâmetro genérico T.
  • Para cada propriedade K, deve haver um método setK (com K capitalizado).
  • O método setK deve receber um parâmetro do tipo T[K] e retornar void.
  • O tipo resultante não deve ter as propriedades originais, apenas os setters.

Código inicial

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

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

const setters: Setters<Usuario> = {
  setNome: (v) => { console.log(`Nome: ${v}`); },
  setIdade: (v) => { console.log(`Idade: ${v}`); },
};

setters.setNome("Ana");
setters.setIdade(30);

Saída esperada

Nome: Ana
Idade: 30
Ver dica

Use [K in keyof T as set${Capitalize<string & K>}]: (value: T[K]) => void.

Mostrar solução
type Setters<T> = {
  [K in keyof T as `set${Capitalize<string & K>}`]: (value: T[K]) => void;
};

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

const setters: Setters<Usuario> = {
  setNome: (v) => { console.log(`Nome: ${v}`); },
  setIdade: (v) => { console.log(`Idade: ${v}`); },
};

setters.setNome("Ana"); // Nome: Ana
setters.setIdade(30); // Idade: 30

Passo a passo

  1. Definimos Setters<T> como um mapped type genérico.
  2. Usamos [K in keyof T as ...] para iterar sobre as chaves e remapeá-las.
  3. A expressão as \set${Capitalize<string & K>}`cria um novo nome de chave:set` + chave capitalizada.
  4. O tipo string & K é necessário porque K pode ser string | number | symbol; Capitalize só aceita string.
  5. O valor associado é uma função (value: T[K]) => void.
  6. No teste, criamos um objeto setters que implementa os métodos.
  7. Chamamos setNome e setIdade, que imprimem os valores.

Por que funciona

O remapeamento com as permite alterar os nomes das chaves durante a criação do mapped type. A interseção string & K restringe K a string para que Capitalize possa ser aplicado. O tipo resultante tem apenas as chaves remapeadas, cada uma com o tipo de função correto. Isso é útil para gerar APIs de setters ou getters automaticamente.

Erros comuns

  • Esquecer string & K: Capitalize<K> gera erro porque K pode não ser string.
  • Usar Capitalize<K> sem o & string: o TypeScript reclama que K não satisfaz a restrição string.
  • Não usar template literal: as 'set' + K não é válido em tipos; é preciso usar template literal types.
  • Deixar as propriedades originais: o remapeamento com as substitui as chaves; se quiser manter, use interseção com T.

Outra forma de resolver

Se quiser manter as propriedades originais e adicionar setters, use:

type SettersAndProps<T> = T & {
  [K in keyof T as `set${Capitalize<string & K>}`]: (value: T[K]) => void;
};

Isso é útil quando você precisa tanto dos dados quanto dos setters.

Saída esperada

Nome: Ana
Idade: 30