Desafio TypeScript

Validador de campos com keyof e typeof

Enunciado

Crie um objeto formulario com campos nome (string), idade (number) e email (string). Implemente uma função validarCampo que recebe o objeto, uma chave e uma função de validação específica para o tipo daquele campo. A função deve retornar true se o valor passar na validação. Use tipos genéricos e indexados para garantir que a função de validação receba o tipo correto. Teste com três campos e imprima os resultados.

Requisitos

  • O tipo da chave deve ser keyof T.
  • A função de validação deve receber T[K] como parâmetro.
  • A função validarCampo deve retornar boolean.
  • O código deve compilar sem erros e imprimir true ou false para cada teste.

Código inicial

const formulario = {
  nome: "",
  idade: 0,
  email: "teste@exemplo.com",
};

// Implemente validarCampo e os testes

Saída esperada

nome: false
idade: true
email: true
Ver dica

A assinatura pode ser function validarCampo<T, K extends keyof T>(obj: T, chave: K, validador: (valor: T[K]) => boolean): boolean. Retorne validador(obj[chave]).

Mostrar solução
const formulario = {
  nome: "",
  idade: 0,
  email: "teste@exemplo.com",
};

// Valida se o campo atende à regra específica
function validarCampo<T, K extends keyof T>(
  obj: T,
  chave: K,
  validador: (valor: T[K]) => boolean
): boolean {
  return validador(obj[chave]);
}

// Testes com validadores específicos por tipo
const nomeValido = validarCampo(formulario, "nome", (v) => v.length > 0);
const idadeValida = validarCampo(formulario, "idade", (v) => v >= 18);
const emailValido = validarCampo(formulario, "email", (v) => v.includes("@"));

console.log(`nome: ${nomeValido}`);
console.log(`idade: ${idadeValida}`);
console.log(`email: ${emailValido}`);

Passo a passo

  1. Definimos formulario com três campos de tipos distintos.
  2. A função validarCampo é genérica em T e K extends keyof T.
  3. O terceiro parâmetro é uma função validador que recebe T[K], o tipo exato do campo selecionado.
  4. Dentro da função, chamamos validador(obj[chave]) e retornamos o booleano resultante.
  5. No teste de nome, o validador recebe string e verifica se o comprimento é maior que zero.
  6. No teste de idade, o validador recebe number e verifica se é maior ou igual a 18.
  7. No teste de email, o validador recebe string e verifica se contém @.
  8. Imprimimos os resultados no formato pedido.

Por que funciona

O uso de T[K] no parâmetro validador garante que a função de validação receba exatamente o tipo da propriedade escolhida. O TypeScript infere K a partir da string literal passada e verifica se o validador é compatível. Isso permite criar APIs flexíveis e seguras, sem casts e sem perda de tipagem.

Erros comuns

  • Tipar o validador como (valor: any) => boolean: perde a segurança e não demonstra o conceito.
  • Usar keyof T sem restringir K: function validarCampo<T>(obj: T, chave: keyof T, validador: (v: T[keyof T]) => boolean) faz o validador receber a união de todos os tipos, dificultando a escrita.
  • Passar uma chave inexistente: validarCampo(formulario, "telefone", ...) gera erro de compilação.
  • Esquecer de retornar o resultado: a função deve retornar validador(obj[chave]), não apenas chamá-lo.

Outra forma de resolver

Poderia usar um mapa de validadores por chave, mas a função genérica é mais flexível e reutilizável. Também é possível usar sobrecargas, mas os genéricos são mais limpos.

Saída esperada

nome: false
idade: true
email: true