Pular para o conteúdo principal
Módulo 5 · Lição 1 de 29/14 no curso~15 min
Lições do módulo (1/2)

Tipo Guardas

O estreitamento de tipo é um dos conceitos mais importantes do TypeScript. Muitas vezes, porém, proteções de tipo padrão como typeof ou instanceof não são suficientes para objetos personalizados complexos. É aqui que entram os Protetores de tipo personalizado.

Protetores de tipo padrão

Vamos começar resumindo como o TypeScript restringe os tipos usando operadores JavaScript padrão:

TS
function processInput(val: string | number) {
  if (typeof val === 'string') {
    // Here 'val' is of type string
    console.log(val.toUpperCase());
  } else {
    // Here 'val' is of type number
    console.log(val.toFixed(2));
  }
}

Protetores de tipo personalizados (operador is)

Para definir uma proteção de tipo personalizada, criamos uma função que retorna um predicado de tipo no formato parameterName is Type em vez de um tipo de retorno booleano padrão.

A função deve retornar um booleano (true ou false). Se retornar true, o TypeScript saberá que o parâmetro passado é do tipo especificado.

TS
interface Cat {
  name: string;
  meow(): void;
}

interface Dog {
  name: string;
  bark(): void;
}

// This is a custom type guard
function isCat(animal: Cat | Dog): animal is Cat {
  return (animal as Cat).meow !== undefined;
}

function makeNoise(pet: Cat | Dog) {
  if (isCat(pet)) {
    // Here TypeScript knows 'pet' is a Cat
    pet.meow();
  } else {
    // Here TypeScript knows 'pet' is a Dog
    pet.bark();
  }
}

Segurança e fundição (as vs protetores de tipo)

A conversão de tipo (por exemplo, val as Cat) força o compilador a confiar no desenvolvedor sem qualquer verificação real em tempo de execução. Se o objeto de tempo de execução não atender às expectativas, o código falhará silenciosamente ou lançará exceções.

Os protetores de tipo personalizados, por outro lado, realizam uma verificação de tempo de execução robusta e dinâmica, informando com segurança e precisão ao compilador TypeScript o tipo real da variável:

TS
function processInput(input: unknown) {
  // unsafe casting: could crash if input does not have the split method
  // const str = input as string;
  // console.log(str.split(' '));

  // safe guard
  if (isString(input)) {
    console.log(input.split(' ')); // 100% Safe!
  }
}

Experimente você mesmo

Exercício 1: Guarda Tipo String

Exercício#ts.m5.l1.e1
Tentativas: 0Carregando…

Crie uma função simples chamada isString que atue como um protetor de tipo personalizado para verificar se um valor desconhecido é uma string.

Carregando editor…
Mostrar dica

O tipo de retorno da função deve ser val is string, e você deve usar typeof para verificar se é igual a ‘string’.

Solução disponível após 3 tentativas

Exercício 2: Proteção de Tipo de Usuário Premium

Exercício#ts.m5.l1.e2
Tentativas: 0Carregando…

Dados os tipos User e PremiumUser, escreva uma função de proteção de tipo isPremiumUser(user: User): user is PremiumUser que verifica se o usuário tem a função 'premium'.

Carregando editor…
Mostrar dica

Defina a assinatura como função isPremiumUser(user: User): user is PremiumUser e compare user.role com 'premium'.

Solução disponível após 3 tentativas

Exercício 3: Validação de objeto de erro personalizado

Exercício#ts.m5.l1.e3
Tentativas: 0Carregando…

Implemente a função isCustomError(err: desconhecido): err is CustomError que verifica se um valor desconhecido é um objeto CustomError não nulo contendo a chave 'código'.

Carregando editor…
Mostrar dica

Primeiro verifique se typeof err é 'objeto' e não nulo e, em seguida, use o operador 'in' para verificar a propriedade 'código'.

Solução disponível após 3 tentativas

Exercício 4: Admin Type Guard

Exercício#ts.m5.l1.e4
Tentativas: 0Carregando…

Dadas duas interfaces User (com propriedade role: string) e Admin (estendendo User e tendo uma propriedade adminToken: string), escreva uma função de proteção de tipo chamada isAdmin que aceita um usuário do tipo User e retorna um predicado de tipo user is Admin. O guarda deve verificar se a função do usuário é igual a ‘admin’.

Carregando editor…
Mostrar dica

Defina a assinatura como função isAdmin(user: User): user é Admin e verifique se user.role === 'admin'.

Solução disponível após 3 tentativas