Tipos condicionais TypeScript

Tipos condicionais em TypeScript fornecem uma maneira de criar tipos que dependem de uma condição. Eles permitem maior flexibilidade e expressividade em definições de tipo, tornando possível modelar relacionamentos de tipo complexos de forma clara e concisa. Este artigo explora como tipos condicionais funcionam em TypeScript e fornece exemplos para ilustrar seu uso.

O que são tipos condicionais?

Tipos condicionais permitem a criação de tipos que são selecionados com base em uma condição. Eles são semelhantes a instruções condicionais em programação, mas operam no nível de tipo. A sintaxe básica de um tipo condicional é:

type ConditionalType = T extends U ? X : Y;

Nesta sintaxe:

  • T é o tipo que está sendo verificado.
  • U é o tipo com o qual se deve comparar.
  • X é o tipo retornado se T estende U.
  • Y é o tipo retornado se T não estende U.

Exemplo básico de tipos condicionais

Aqui está um exemplo simples de um tipo condicional que retorna tipos diferentes com base no fato de um determinado tipo ser uma string ou não:

type IsString = T extends string ? "String" : "Not a string";

type Result1 = IsString;  // Result1 is "String"
type Result2 = IsString;  // Result2 is "Not a string"

Neste exemplo, IsString verifica se T estende string. Se estender, o resultado é "String"; caso contrário, é "Not a string".

Usando tipos condicionais com tipos genéricos

Tipos condicionais também podem ser usados ​​com tipos genéricos para criar definições de tipo mais flexíveis e reutilizáveis. Por exemplo, um tipo que extrai o tipo de retorno de uma função:

type ReturnType = T extends (...args: any[]) => infer R ? R : never;

type FunctionType = (x: number) => string;

type Result = ReturnType;  // Result is string

Neste exemplo, ReturnType usa a palavra-chave infer para inferir o tipo de retorno R do tipo de função T. Se T for um tipo de função, ReturnType será o tipo de retorno; caso contrário, o padrão será never.

Tipos condicionais com tipos de união

Tipos condicionais também podem trabalhar com tipos de união para lidar com múltiplos tipos possíveis. Por exemplo, distinguir entre diferentes membros de união:

type ExtractString = T extends string ? T : never;

type UnionType = string | number | boolean;

type Result = ExtractString;  // Result is string

Neste exemplo, ExtractString extrai string de um tipo de união UnionType, resultando em string.

Tipos condicionais com mapeamentos de tipos

Tipos condicionais podem ser combinados com mapeamentos de tipos para criar transformações de tipos mais complexas. Por exemplo, mapeando sobre uma matriz de tipos para aplicar um tipo condicional:

type MapArray = {
  [K in keyof T]: T[K] extends string ? T[K] : never;
};

type ArrayType = [string, number, boolean];

type MappedArray = MapArray;  // MappedArray is [string, never, never]

Neste exemplo, MapArray mapeia cada elemento da matriz T e aplica um tipo condicional a cada elemento, resultando em uma matriz onde apenas elementos de string são preservados.

Conclusão

Tipos condicionais em TypeScript são uma ferramenta poderosa para criar definições de tipo flexíveis e expressivas. Ao alavancar tipos condicionais, os desenvolvedores podem modelar relacionamentos de tipo complexos, lidar com vários cenários e melhorar a segurança de tipo em seu código TypeScript. Entender como usar tipos condicionais efetivamente pode aumentar significativamente a capacidade de escrever código TypeScript robusto e sustentável.