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

Sindicatos e Estreitamento

No mundo real, as variáveis ​​e as respostas da API nem sempre têm um único tipo fixo. O TypeScript oferece Union Types para lidar com a variabilidade e Type Narrowing para operar com segurança neles em tempo de execução.


Tipos de união

Um tipo de união permite que uma variável aceite valores de tipos diferentes. É expresso usando o símbolo da barra vertical (|):

TS
let result: number | string;
result = 42; // Valid
result = 'Error 404'; // Valid

Porém, ao trabalhar com um tipo união, não podemos chamar diretamente métodos que pertencem a apenas um dos tipos (por exemplo, não podemos chamar .toUpperCase() se a variável também puder ser number). Devemos primeiro "estreitar" o tipo.


Estreitamento de tipo

Estreitamento de tipo é o processo em que o TypeScript analisa estruturas de fluxo de controle (como if ou switch) para deduzir um tipo mais específico para uma variável em tempo de execução.

Existem várias maneiras de realizar o estreitamento:

1. O Operador typeof

Ideal para distinguir tipos primitivos:

TS
function printLength(value: string | number) {
  if (typeof value === 'string') {
    // TypeScript knows 'value' is a string here
    console.log(value.length);
  } else {
    // TypeScript knows 'value' is a number here
    console.log(value.toFixed(2));
  }
}

2. O Operador in

Usado para verificar se existe uma propriedade específica em um objeto:

TS
interface Fish {
  swim: () => void;
}
interface Bird {
  fly: () => void;
}

function move(animal: Fish | Bird) {
  if ('swim' in animal) {
    animal.swim(); // Narrowing to Fish
  } else {
    animal.fly(); // Narrowing to Bird
  }
}

Sindicatos Discriminados

O padrão Uniões Discriminadas consiste na criação de objetos que compartilham uma propriedade comum com um valor literal exclusivo (chamado de discriminador). O TypeScript reconhece esse discriminador e restringe automaticamente o tipo dentro de blocos condicionais.

TS
interface SuccessResponse {
  status: 'success'; // Literal discriminator
  data: string;
}

interface ErrorResponse {
  status: 'error'; // Literal discriminator
  errorMessage: string;
}

type ApiResponse = SuccessResponse | ErrorResponse;

function handleResponse(response: ApiResponse) {
  if (response.status === 'success') {
    console.log('Data received:', response.data);
  } else {
    console.error('An error occurred:', response.errorMessage);
  }
}

Experimente você mesmo

Exercício 1: Tipos de união

Exercício#ts.m2.l2.e1
Tentativas: 0Carregando…

Declare uma variável chamada id que pode ser um número ou uma string. Inicialize-o primeiro com o número 101 e, em seguida, atribua o valor da string 'USER-101'.

Carregando editor…
Mostrar dica

Use o | operador para juntar número e string na declaração da variável let.

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

Exercício 2: Estreitamento de Tipo Básico

Exercício#ts.m2.l2.e2
Tentativas: 0Carregando…

Crie uma função chamada formatInput que aceite uma entrada de parâmetro do tipo string ou número. Se a entrada for uma string, retorne a entrada convertida em maiúsculas. Se for um número, retorne a entrada multiplicada por 2. Especifique os tipos explicitamente.

Carregando editor…
Mostrar dica

Use typeof input === 'string' dentro de um bloco if para ramificar o comportamento.

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

Exercício 3: Estreitando com 'in'

Exercício#ts.m2.l2.e3
Tentativas: 0Carregando…

Dadas as duas interfaces Car (com método drive) e Boat (com método vela), escreva uma função chamada moveVehicle que aceita um parâmetro veículo do tipo Car ou Boat. Se o veículo tiver a propriedade drive, execute o método drive(). Caso contrário, execute o método Sail().

Carregando editor…
Mostrar dica

Use o operador in no formato 'dirigir' no veículo para restringir a interface.

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

Exercício 4: Forma de União Discriminada

Exercício#ts.m2.l2.e4
Tentativas: 0Carregando…

Defina um tipo Shape que é a união de dois tipos: Círculo e Quadrado. Círculo tem uma propriedade de tipo definida como 'círculo' (valor literal) e um raio (número). Square tem uma propriedade de tipo definida como 'quadrado' (valor literal) e um lado (número). Em seguida, escreva uma função getArea que aceite forma do tipo Shape e retorne a área como um número (para círculo Math.PI * raio * raio, para lado quadrado * lado).

Carregando editor…
Mostrar dica

Use shape.kind === 'circle' dentro de getArea para discriminar o tipo e calcular a área correta.

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