DEV Community

Mago AcadĂȘmico
Mago AcadĂȘmico

Posted on

đŸ§™â€â™‚ïž Aprenda Conditional Types no TypeScript

Se vocĂȘ quer levar seu conhecimento de TypeScript para o prĂłximo nĂ­vel, vocĂȘ precisa entender sobre Conditional Types (Tipos Condicionais). Aprender isso com certeza irĂĄ te colocar na frente da maioria dos desenvolvedores Typescript, jĂĄ que poucos conhecem sobre.

Antes de tudo: Conceitos fundamentais

Para entender os Conditional Types, Ă© necessĂĄrio dominar trĂȘs conceitos do TypeScript:

  • Generics
  • extends
  • TernĂĄrio

1. Generics

Leia esse outro artigo que fiz caso vocĂȘ nĂŁo saiba o que Ă©:

2. Extends

Usado para impor que um tipo herda (ou estende) outro tipo.

interface A {
  name: string;
}

// B tem todas as propriedades de A
interface B extends A {
  age: number;
}
Enter fullscreen mode Exit fullscreen mode

Nos Conditional Types, o extends Ă© usado como parte de uma condição (nĂŁo Ă© a mesma funcionalidade do examplo, mas vocĂȘ irĂĄ entender mais pra frente)

3. Operador TernĂĄrio

Muito conhecido de outras linguagens, o ternårio permite retornar valores diferentes baseado em uma condição:

condição ? valorSeVerdadeiro : valorSeFalso
Enter fullscreen mode Exit fullscreen mode

Esses trĂȘs elementos formam a base dos Conditional Types.


O que sĂŁo Conditional Types?

Um Conditional Type permite criar um tipo baseado em uma condição lógica entre dois tipos.

A base dos Conditional Types:

Usar um Conditional Types, nada mais Ă© do que vocĂȘ colocar uma verificação no seu tipo, onde vocĂȘ usa extends para verificar e usa o ternĂĄrio para retornar o tipo dependendo da verificação.

type Teste<T> = T extends string ? true : false;

type A = Teste<string>; // true
type B = Teste<number>; // false
Enter fullscreen mode Exit fullscreen mode

Aqui, o tipo Teste verifica se T Ă© uma string. Se sim, retorna true, senĂŁo false.

Para simplificar, vocĂȘ pode imaginar o seguinte:

  • T extends string => T === string
  • ... ? true : false; => if(...) { return true } else { return false }

A syntax pode parecer complicada, mas vocĂȘ pode imaginar como se fosse vĂĄrios if e else.


Usos prĂĄticos com Conditional Types

1. Remover tipos null ou undefined

O TypeScript jĂĄ possui o tipo NonNullable, mas ele pode ser recriado usando Conditional Types:

type NonNullableCustom<T> = T extends null | undefined ? never : T;
Enter fullscreen mode Exit fullscreen mode
type A = NonNullableCustom<string | null>; // string
Enter fullscreen mode Exit fullscreen mode

Nesse caso, para "excluir" um tipo, vocĂȘ retorna o tipo never.

2. Recriando o tipo Extract

O TypeScript jĂĄ possui o tipo Extract, mas ele pode ser recriado usando Conditional Types:

type ExtractCustom<T, U> = T extends U ? T : never;
Enter fullscreen mode Exit fullscreen mode

Por exemplo:

type A = ExtractCustom<string | number, string>; // string
Enter fullscreen mode Exit fullscreen mode

Nesse caso, vocĂȘ pode ver como Ă© possĂ­vel passar vĂĄrios parĂąmetros genĂ©ricos e usa-los nas condiçÔes.


Recursividade com Conditional Types

Como exemplo, suponha que vocĂȘ quer extrair qual Ă© o tipo de um array. No Typescript, vocĂȘ pode usar [number] para accessar o tipo do array.

type ArrayValue<T extends any[]> = T[number];

type A = ArrayValue<string[]>; // => string
// Mesma coisa que fazer "string[][number]" => string
Enter fullscreen mode Exit fullscreen mode

Mas esse exemplo tem um problema, porque ele não funciona para arrays de multiplas dimensÔes:

type ArrayValue<T extends any[]> = T[number];

type A = ArrayValue<string[][]>; // => string[], mas era para ser apenas string
Enter fullscreen mode Exit fullscreen mode

E Ă© ai que entra o Conditional Types para resolver esse problema.

Porque no Conditional Types, vocĂȘ pode chamar o prĂłprio tipo recursivamente

type DeepArrayValue<T> = T extends any[] // verifica se Ă© um array qualquer
  ? DeepArrayValue<T[number]> // extrai o tipo do array e passa de novo para o prĂłprio tipo
  : T; // retorna o tipo quando ele nĂŁo Ă© mais um array

type A = DeepArrayValue<string[][][]>; // string
Enter fullscreen mode Exit fullscreen mode

VocĂȘ poderia "traduzir" o cĂłdigo a cima como se fosse um if e else da seguinte forma:

function DeepArrayValue(T) {
  if(T === qualquer_array) { // verifica se Ă© um array qualquer
    const tipo_do_array = T[number] // extrai o tipo do array
    return DeepArrayValue(tipo_do_array) // chama de novo a função com o tipo extraido
  } else {
    return T // retorna o tipo quando ele nĂŁo Ă© mais um array qualquer
  }
}
Enter fullscreen mode Exit fullscreen mode

Para acabar com a recursividade, vocĂȘ acaba retornando o prĂłprio T quando ele nĂŁo Ă© mais um "array qualquer".


ConsideraçÔes Finais

Conditional Types Ă© extremamente poderosos no TypeScript e com ele foi criado a maioria dos tipos jĂĄ existentes (como o NonNullable e Extract que vimos anteriormente)

NĂŁo vai ser todos os dias que vai criar um Conditional Types do zero, mas pode ter certeza que vocĂȘ vai usar bastante algum tipo jĂĄ existente do Typescript que usa ele e por isso Ă© sempre bom entender como funciona o Conditional Types.


Esse artigo foi baseado no meu vĂ­deo: Apenas 1% dos devs sabem disso no TypeScript

Se tiver dĂșvidas ou sugestĂ”es, deixe nos comentĂĄrios!

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.