Desafio TypeScript
Filtro tipado com guard reutilizável
Enunciado
Dada uma lista de itens que podem ser Produto ou Servico, crie um type guard isProduto e use-o para filtrar apenas os produtos. Depois, calcule o valor total dos produtos (preço * quantidade) e imprima. Defina as interfaces Produto (com tipo: 'produto', preco: number, quantidade: number) e Servico (com tipo: 'servico', descricao: string).
Requisitos
- O type guard
isProdutodeve ter assinatura(item: Produto | Servico): item is Produto. - Use
Array.prototype.filtercom o guard para obter um array deProduto[]. - Calcule e imprima o valor total dos produtos no formato
Total: R$ X.
Código inicial
interface Produto {
tipo: 'produto';
preco: number;
quantidade: number;
}
interface Servico {
tipo: 'servico';
descricao: string;
}
type Item = Produto | Servico;
// implemente isProduto e o cálculo
const itens: Item[] = [
{ tipo: 'produto', preco: 10, quantidade: 2 },
{ tipo: 'servico', descricao: 'Consultoria' },
{ tipo: 'produto', preco: 5, quantidade: 3 },
];
Saída esperada
Total: R$ 35
Ver dica
O guard pode verificar item.tipo === 'produto'. No filter, use itens.filter(isProduto) e depois reduce.
Mostrar solução
interface Produto {
tipo: 'produto';
preco: number;
quantidade: number;
}
interface Servico {
tipo: 'servico';
descricao: string;
}
type Item = Produto | Servico;
function isProduto(item: Item): item is Produto {
return item.tipo === 'produto';
}
const itens: Item[] = [
{ tipo: 'produto', preco: 10, quantidade: 2 },
{ tipo: 'servico', descricao: 'Consultoria' },
{ tipo: 'produto', preco: 5, quantidade: 3 },
];
const produtos: Produto[] = itens.filter(isProduto);
const total = produtos.reduce((acc, p) => acc + p.preco * p.quantidade, 0);
console.log(`Total: R$ ${total}`);
Passo a passo
- Definimos as interfaces
ProdutoeServicocom a propriedade discriminantetipo. - Criamos o type guard
isProdutoque verificaitem.tipo === 'produto'e retornaitem is Produto. - Declaramos o array
itenscom elementos dos dois tipos. - Usamos
itens.filter(isProduto). O TypeScript reconhece o predicado e o array resultante éProduto[]. - Calculamos o total com
reduce, multiplicandopreco * quantidadede cada produto. - Imprimimos o total formatado.
Por que funciona
O type guard isProduto informa ao compilador que, quando retorna true, o item é Produto. O método filter aceita um predicado de tipo e, por isso, o array resultante é tipado como Produto[]. Assim, podemos acessar preco e quantidade sem erros de compilação.
Erros comuns
- Não usar o guard no filter:
itens.filter(item => item.tipo === 'produto')retornaItem[], e acessarp.precogera erro. - Esquecer o
isno retorno:function isProduto(item: Item): booleannão estreita o tipo no filter. - Usar
instanceofem interfaces: interfaces não existem em runtime; use a propriedade discriminante.
Outra forma de resolver
Usar um type predicate inline no filter:
const produtos = itens.filter((item): item is Produto => item.tipo === 'produto');
Isso é útil quando o guard não será reutilizado, mas menos legível.
Saída esperada
Total: R$ 35