Uma introdução aos tipos avançados do TypeScript
Tags: typescript, tutorial, programming
Published: 2022-07-21 02:41:23


![TS symbol](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x649br6rt12yr2w80kxu.png)


## Por qual razão se usa TypeScript ? 

A resposta parece obvia, por tipos é claro. Hoje quero escrever mais a fundo sobre os avançados do TypeScript. Antes de tudo vou deixar um link com uma referencia dentro do typescript sobre o seu sistema de tipos o _Structural Subtyping_ o [link](https://www.typescriptlang.org/play#example/structural-typing) é extremamente interessante para quem gostaria de ter um entendimento da base da linguagem.

Sem mais delongas eu começo falando de uma funcionalidade que combina muito com o DRY/ Funções Helpers, funções que são genericas que muitas vezes são reescritas apenas para fazer a mesma coisa com aquele tipo especifico.

### Generics

Um exemplo basico de Generics é de criar funções que fazem coisas repetidas. Nesse caso para exemplificar eu diria uma função que envia algo para algum lugar e retorna o mesmo.

```TypeScript

function fooToBar<foo, bar>(arg: Array<foo>): Array<bar> {
  // faz algo com foo e por fim faz bar, Geralmente vejo sendo usado com arrays uma vez que arrays possuem muitas funções que pode ser necessario reutilizar 
  const bar = makeBarUsingFoo(arg);
  return arg;
}

```
_uso basico de genericos_

O objetivo principal de generics é como seu proprio nome diz criar coisas genericas que *_VÃO_* te ajudar como funções helpers. Assim como em outras langs os genéricos criam esse desacomplamento de código da mesma forma que dão funcionalidade e expressividade. Funfact: Chamar o type de array de maneira generica possui semanticamente o mesmo resultado que sua versão curta: 
```ts

Array<Type> === Type[] 

 ```

### keyof 

Esse é um tópico que me lembra PHP vagamente pois Objetos em JavaScript e TypeScript possuem similaridade com Arrays Associativos em PHP.
 
obj.foo e obj['foo'] é a mesma forma de acessar um objeto, isso pode ser um problema caso a string de acesso esteja errada, para conter isso e criar ambientes dinamicos e bem interessantes, podemos usar a palavra reservada keyof.

```TypeScript

type fooBar = { foo: boolean, bar: boolean };
let fbKey: keyof fooBar; // fbKey só pode assumir os valores de 'foo' ou 'bar'

// você pode acessar um objeto como o fooBar dessas maneiras
obj: fooBar;
const a = obj.foo // usando a notação de ponto
const z = obj['foo'] // aqui ele SÓ deixa os valores que são chaves do type  

```
 _exemplo sobre a palavra reservada keyof_

### in operator e o instanceof

Essa keyword quando usada com interfaces pode deixar ambientes dinamicos bem previsiveis o que torna o dia dia muito mais fácil e claro. Lembrando que funciona apenas com interfaces e classes, enquanto o _in_ funciona em types. Para exemplificar eu gosto desse modelo: 

```TypeScript
class foo { fooMethod() {}}
class bar { barMethod() {}}
class bla { blaMethod() {}}
function doSomething(x: foo | bar | bla) {
  if (x instanceof foo) {
    x.fooMethod() // função que só tem em foo ou chamar função só aceita foo
  }
  if (x instanceof bar) {
    x.barMethod() // função que só tem em bar ou chamar função só aceita bar
  }
  if (x instanceof bla) {
    x.blaMethod() // função que só tem em bla ou chamar função só aceita bla
  }
}

// outra forma é usando o in caso 
type foo = { foo: string}
type bar = { bar: string}
function doSomething(x: foo | bar ) {
  if ("foo" in x) {
    // função que só tem em foo ou chamar função só aceita foo
    onlyFoo(x);
  }
  if ("bar" in x) {
    onlyBar(x) // função que só tem em bar ou chamar função só aceita bar
  }
}
function onlyFoo(p: foo){}
function onlyBar(p: bar){}

```
_exemplo de in e instanceof_ 

Ambos modelos podem ser uteis em criar roteamento em funções para lidar com dinamicidades do código.

### Template Literals

Esse é um tópico que eu amo pois ajuda muito em relação a lidar com dados com nomes _MUITO_ parecidos que podem ser de qualquer lugar.

A documentação do TypeScript nós dá um exemplo que eu considero maravilhoso.

```TypeScript

type EmailLocaleIDs = "welcome_email" | "email_heading";
type Lang = "en" | "ja" | "pt";
 
type LocaleMessageIDs = `${Lang}_${EmailLocaleIDs}`; // esse type pode ser -> "en_welcome_email" | "en_email_heading" | "ja_welcome_email" | "ja_email_heading" | "pt_welcome_email" | "pt_email_heading"

```
_Exemplo de Template Literal_

Esse use case que a doc dá [aqui](https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html) é surrealmente útil uma vez que dessa forma deixamos N formas de chamar algum valor em algum lugar pronto apenas por fazer essa únião de valores. Uma multiplicação relativamente simples mas que salva muito tempo. ao invés de escrever os 6 nomes que podem ser chamados, escreve-se apenas 5 nomes, parece pouca vantagem mas quando se tem 4 linguas o type nós auto-gera 8 possiveis types, caso tivesse 4 linguas e 5 emails temos mapeado 20 possibilidades, enquanto escrevemos apenas 9 variavéis.


## Conclusão
De maneira geral os tipos avançados em TypeScript são ou apenas usando alguma dessas funcionalidades que eu expliquei ou alguma combinação das mesmas para criar funcionalidades que vão ser uteis no futuro sem perder a expressividade que essa linguagem nós trás.