Da trilha de TypeScript Este conceito ainda não saiu como card do dia. ir para o card de hoje

TypeScript Tipos Intermediário

Type guards

Em TypeScript, type guards são verificações que estreitam o tipo de uma variável dentro de um bloco condicional. O compilador entende typeof, instanceof, in e comparações literais como guards nativos. Para casos personalizados, criamos funções que retornam um predicado de tipo (value is T), informando ao compilador que aquele valor é do tipo T quando a função retorna true.

Além dos predicados, o TypeScript 3.7 introduziu assertion functions (asserts value is T). Elas não retornam booleano; se a função não lançar erro, o compilador assume que a condição é verdadeira e estreita o tipo dali em diante. Isso é útil para validar entradas e evitar repetição de if.

Guards reutilizáveis encapsulam lógica de verificação em um único lugar, mantendo o código DRY e seguro. Também podemos usá-los em métodos de array como filter, mas o TypeScript não infere o tipo automaticamente a partir do predicado; é preciso usar um type predicate na assinatura do callback ou uma anotação explícita.

Neste card, vamos explorar predicados x is T, assertions, guards reutilizáveis e filtros tipados com exemplos práticos.

Pontos-chave

  • typeof, instanceof, in e comparações literais são type guards nativos do TypeScript.
  • Funções com retorno value is T criam predicados de tipo personalizados e reutilizáveis.
  • asserts value is T declara uma assertion function que estreita o tipo após a chamada.
  • Em Array.prototype.filter, use (x): x is T => ... para que o array resultante tenha o tipo correto.
  • Type guards não existem em tempo de execução; são apenas para o sistema de tipos.
type_guards.ts
// Exemplo completo de type guards em TypeScript

// 1. Predicado de tipo personalizado
interface Cat {
  kind: 'cat';
  meow(): void;
}

interface Dog {
  kind: 'dog';
  bark(): void;
}

type Animal = Cat | Dog;

// Predicado: retorna true se o valor for Cat
function isCat(animal: Animal): animal is Cat {
  return animal.kind === 'cat';
}

// 2. Assertion function
function assertIsCat(animal: Animal): asserts animal is Cat {
  if (animal.kind !== 'cat') {
    throw new Error('Não é um gato!');
  }
}

// 3. Guard reutilizável para filtrar arrays
function filterCats(animals: Animal[]): Cat[] {
  return animals.filter(isCat); // filter tipado com predicado
}

// Uso
const animals: Animal[] = [
  { kind: 'cat', meow: () => console.log('Miau') },
  { kind: 'dog', bark: () => console.log('Au au') },
  { kind: 'cat', meow: () => console.log('Miau') },
];

const cats = filterCats(animals);
cats.forEach(cat => cat.meow()); // OK: cats é Cat[]

// Assertion em ação
const maybeCat: Animal = { kind: 'cat', meow: () => console.log('Miau') };
assertIsCat(maybeCat);
maybeCat.meow(); // Compilador sabe que é Cat

Exercícios

  1. 1
    Fácil

    Predicado para string ou number

    Crie uma função isString que recebe um valor do tipo string | number e retorna um predicado de tipo value is string. Depois, use-a para imprimir o valor em maiúsculas se for string, ou o dobro se for number.

    Resolver
  2. 2
    Médio

    Assertion function para validar entrada

    Crie uma função assertIsNumber que recebe um valor unknown e usa asserts value is number. Se o valor não for número, lance um erro com a mensagem 'Valor não é número'. Depois, use-a para validar uma entrada e somar 10.

    Resolver
  3. 3
    Desafio

    Filtro tipado com guard reutilizável

    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).

    Resolver

Continue estudando