Desafio TypeScript

Narrowing com união discriminada e análise de fluxo

Enunciado

Defina uma união discriminada Resultado que representa o resultado de uma operação: { sucesso: true, valor: number } ou { sucesso: false, erro: string }. Implemente uma função processar que recebe um Resultado e retorna uma string descritiva. Use narrowing por igualdade na propriedade sucesso. Além disso, trate o caso em que a entrada pode ser null ou undefined usando narrowing com typeof ou verificação de nulidade.

Requisitos

  • Definir o tipo Resultado como união discriminada.
  • Usar if (resultado.sucesso) para estreitar.
  • Tratar null | undefined antes de acessar propriedades.
  • Retornar string em todos os caminhos.

Código inicial

type Resultado =
  | { sucesso: true; valor: number }
  | { sucesso: false; erro: string };

function processar(resultado: Resultado | null | undefined): string {
  // Seu código aqui
}

console.log(processar({ sucesso: true, valor: 42 }));
console.log(processar({ sucesso: false, erro: 'Falha' }));
console.log(processar(null));

Saída esperada

Sucesso: 42
Erro: Falha
Sem resultado
Ver dica

Primeiro verifique se resultado é null ou undefined. Depois use resultado.sucesso para distinguir os casos.

Mostrar solução
type Resultado =
  | { sucesso: true; valor: number }
  | { sucesso: false; erro: string };

function processar(resultado: Resultado | null | undefined): string {
  if (resultado == null) {
    return 'Sem resultado'; // trata null e undefined
  }
  if (resultado.sucesso) {
    return `Sucesso: ${resultado.valor}`; // resultado é { sucesso: true }
  } else {
    return `Erro: ${resultado.erro}`; // resultado é { sucesso: false }
  }
}

console.log(processar({ sucesso: true, valor: 42 }));
console.log(processar({ sucesso: false, erro: 'Falha' }));
console.log(processar(null));

Passo a passo

  1. Definimos o tipo Resultado como uma união discriminada pela propriedade sucesso.
  2. A função processar aceita Resultado | null | undefined.
  3. Usamos if (resultado == null) para capturar tanto null quanto undefined (o == solto faz essa verificação combinada).
  4. Dentro do if, retornamos a string padrão.
  5. Fora do if, o TypeScript sabe que resultado é Resultado.
  6. Verificamos resultado.sucesso: se true, acessamos valor; se false, acessamos erro.

Por que funciona

A análise de fluxo do TypeScript rastreia o tipo de resultado através dos blocos condicionais. A verificação == null estreita a união removendo null e undefined. Em seguida, a propriedade discriminante sucesso (um literal booleano) permite que o TypeScript saiba exatamente qual variante da união está presente em cada ramo.

Erros comuns

  • Usar if (resultado) para checar null: isso também rejeita { sucesso: false } porque objetos são truthy, mas pode confundir. Prefira == null.
  • Acessar resultado.valor sem verificar sucesso:
    return resultado.valor; // Erro: Property 'valor' does not exist on type '{ sucesso: false; erro: string; }'
  • Esquecer de tratar undefined e receber erro de tipo.

Outra forma de resolver

Usar switch na propriedade sucesso:

switch (resultado?.sucesso) {
  case true: return `Sucesso: ${resultado.valor}`;
  case false: return `Erro: ${resultado.erro}`;
  default: return 'Sem resultado';
}

Útil quando há mais variantes.

Saída esperada

Sucesso: 42
Erro: Falha
Sem resultado