TypeScript Tipos Intermediário
Uniões discriminadas
Uniões discriminadas (discriminated unions) são um padrão de tipagem no TypeScript que permite modelar valores que podem assumir diferentes formas, cada uma com um campo comum que as distingue. Esse campo é chamado de discriminante e geralmente é uma propriedade literal (ex.: type: 'success').
Com uniões discriminadas, o TypeScript consegue refinar o tipo dentro de blocos switch ou if, garantindo que você só acesse propriedades específicas de cada variante. Isso evita erros em tempo de execução e torna o código mais seguro e expressivo.
Além disso, ao usar switch exaustivo com um default que atribui a variável ao tipo never, o compilador acusa se você esquecer de tratar algum caso. Isso é especialmente útil para modelar estados de forma completa, como em máquinas de estado ou resultados de operações assíncronas.
Pontos-chave
- O campo discriminante é uma propriedade literal compartilhada por todas as variantes da união.
- Um
switchsobre o discriminante permite ao TypeScript refinar o tipo em cadacase. - O tipo
neveré usado para garantir exaustividade: se um caso não for tratado, o compilador reclama. - Uniões discriminadas são ideais para modelar estados mutuamente exclusivos, como
loading | success | error. - Evite usar
anyouaspara contornar o refinamento; deixe o compilador inferir os tipos corretos.
// Exemplo de união discriminada para modelar estados de carregamento
type EstadoCarregamento =
| { status: 'carregando' }
| { status: 'sucesso'; dados: string[] }
| { status: 'erro'; mensagem: string };
function renderizar(estado: EstadoCarregamento): string {
switch (estado.status) {
case 'carregando':
return 'Carregando...';
case 'sucesso':
// Aqui, estado é do tipo { status: 'sucesso'; dados: string[] }
return `Dados: ${estado.dados.join(', ')}`;
case 'erro':
// Aqui, estado é do tipo { status: 'erro'; mensagem: string }
return `Erro: ${estado.mensagem}`;
default:
// Garante que todos os casos foram tratados
const exaustivo: never = estado;
return exaustivo;
}
}
// Testando com diferentes estados
console.log(renderizar({ status: 'carregando' }));
console.log(renderizar({ status: 'sucesso', dados: ['a', 'b'] }));
console.log(renderizar({ status: 'erro', mensagem: 'Falha na rede' }));