Fácil TypeScript
Modelando uma forma geométrica
Enunciado
Crie uma união discriminada Forma que represente um círculo, um quadrado e um retângulo. Cada variante deve ter um campo tipo como discriminante e as propriedades específicas. Depois, escreva uma função area(forma: Forma): number que calcule a área usando um switch exaustivo.
Requisitos
- A união
Formadeve ter três variantes:{ tipo: 'circulo'; raio: number },{ tipo: 'quadrado'; lado: number }e{ tipo: 'retangulo'; base: number; altura: number }. - A função
areadeve usarswitchsobreforma.tipoe retornar a área correta. - O
defaultdeve atribuir a variável aneverpara garantir exaustividade.
Código inicial
type Forma = // complete aqui
function area(forma: Forma): number {
// implemente
}
Saída esperada
Área do círculo: 78.53981633974483
Área do quadrado: 16
Área do retângulo: 15
Ver dica
Use Math.PI * raio ** 2 para a área do círculo. Lembre-se de que o discriminante é tipo.
Mostrar solução
type Forma =
| { tipo: 'circulo'; raio: number }
| { tipo: 'quadrado'; lado: number }
| { tipo: 'retangulo'; base: number; altura: number };
function area(forma: Forma): number {
switch (forma.tipo) {
case 'circulo':
return Math.PI * forma.raio ** 2;
case 'quadrado':
return forma.lado ** 2;
case 'retangulo':
return forma.base * forma.altura;
default:
const exaustivo: never = forma;
return exaustivo;
}
}
console.log('Área do círculo:', area({ tipo: 'circulo', raio: 5 }));
console.log('Área do quadrado:', area({ tipo: 'quadrado', lado: 4 }));
console.log('Área do retângulo:', area({ tipo: 'retangulo', base: 5, altura: 3 }));
Passo a passo
- Definimos o tipo
Formacomo uma união de três objetos, cada um com a propriedadetipoque serve como discriminante. - A função
arearecebe um parâmetro do tipoForma. - Dentro do
switch, o TypeScript refina o tipo deformaem cadacasecom base no valor deforma.tipo. - No
case 'circulo', o compilador sabe queformatemraio, então podemos acessá-lo com segurança. - No
case 'quadrado', acessamosladosem erros. - No
case 'retangulo', acessamosbaseealtura. - O
defaultatribuiformaa uma variável do tiponever. Se algum caso não for tratado, o TypeScript acusará erro de compilação. - Chamamos a função com diferentes formas e imprimimos os resultados.
Por que funciona
A união discriminada permite que o TypeScript entenda que cada variante tem um conjunto distinto de propriedades. O campo tipo atua como uma etiqueta que guia o refinamento de tipo dentro do switch. Assim, o compilador garante que você só acesse propriedades que existem naquela variante específica, evitando erros em tempo de execução. O uso de never no default assegura que todos os casos foram cobertos; se um novo tipo for adicionado à união, o compilador forçará você a tratá-lo.
Erros comuns
- Esquecer o
defaultcomnever: sem ele, o TypeScript não avisa se você adicionar uma nova variante e esquecer de tratá-la. Exemplo:default: return 0;não garante exaustividade. - Acessar propriedades sem refinar: tentar
forma.raiofora docase 'circulo'causa erro de compilação, poisraionão existe em todas as variantes. - Usar
anyouas: isso anula a segurança de tipos. Prefira deixar o compilador inferir. - Discriminante não literal: se o campo
tipofor tipado comostringem vez de literais, o refinamento não funciona. Use tipos literais como'circulo'.
Outra forma de resolver
Poderia usar if/else com verificação de tipo, mas o switch é mais idiomático e legível para múltiplas variantes. Exemplo:
if (forma.tipo === 'circulo') return Math.PI * forma.raio ** 2;
// ...
No entanto, o switch com never é superior para garantir exaustividade.
Saída esperada
Área do círculo: 78.53981633974483
Área do quadrado: 16
Área do retângulo: 15