Como usar o typescript a seu favor? (Parte 2)
Tags: typescript, generics, programming, tutorial
Published: 2022-03-30 14:41:55

Falamos bastante sobre algumas coisas basicas do Typescript no [outro post](https://dev.to/matvaleriano/como-usar-o-typescript-a-seu-favor-parte-1-587a). Então que tal irmos além?

# Generics
Isso é bem interessante para cenários que não sabemos exatamente qual tipo de dado sera usado numa função ou algo do tipo. Lembram dos util types? No caso do Pick, por exemplo, vc faz uso de dois generics um para o tipo base que vc quer manipular e o outro para as keys desse tipo. A sintaxe de pick é: `Pick<Type, Keys>`

## Ah mas como eu sei quando usar isso?
Basicamente em funções genéricas, seus próprios util types, conditional types, etc.

## Exemplos
```ts
const foo = <MeuTipo>(value: MeuTipo): MeuTipo => value;

/* caso vc queira usar via type inferrence (ts consegue analisar o seu codigo e definir o tipo)*/
foo(1); // logo value será um number

/* caso vc queira assumir que será um tipo específico */
foo<number>(1); // se vc colocar uma string o ts vai acusar um erro

/* caso vc queira assumir mais de um tipo possível */
foo<string | number>('a'); // a função vai aceitar number ou strings
```

# Custom util types
Para criar o seu próprio util type vc deve ter em mente que ele deve ser simples (pq senão vira um monstrinho) e o que ele deve fazer.

Vc vai precisar usar generics (provavelmente) e vários utils do ts. Bom... vamos aos exemplos.

## WithPrefix (versão 1)
Basicamente vamos adicionar um prefixo para as keys de um Type definido, logo precisaremos de 2 generics (Type e Prefix)

```ts
type WithPrefix<Type, Prefix extends string> = {
    [Key in keyof Type as Key extends string ? `${Prefix}${Capitalize<Key>}` : Key]: Type[Key];
}

type Person = {
    name: string;
    age: number;
};

type PersonWithPrefix = WithPrefix<Person, 'person'>;
```

Agora vamos analizar como isso funciona:
1. Criamos o type WithPrefix recebendo o tipo base e o prefixo (definindo que sempre será uma string. Essa é a função daquele `extends string`)
2. Percorremos todas as keys de Type criando um variável Key que receberá o valor de cada key num loop (por isso aquele `in keyof`).
3. Usamos a expressão `as` para definir uma nova key
4. como existem diversos tipos possíveis na expressão `in keyof Type` tivemos que verificar se a nossa Key é uma string usando a expressão `Key extends string`
5. Utilizamos um ternário para quando a Key for uma string adicionar o prefixo via [string interpolation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals)(a mesma que a gente usa no js/ts do dia a dia). Caso não seja uma string, usará a própria Key. Obs.: O `Capitalize` é um util type do Typescript, ele serve para deixar a primeira letra maiúscula da string que vc inserir no generic. [Veja mais sobre](https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html#capitalizestringtype)
6. Por fim, mas não menos importante demos o valor referente a Key atual do loop para a nossa nova key usando Type[Key]

O retorno disso (se vc passar o mouse em cima no seu vscode) será:
```ts
type PersonWithPrefix = {
    personName: string;
    personAge: number;
}
```
TOP!

Mas e se vc quiser somente para algumas keys???
Bom... aí vamos para a versão 2

## WithPrefix (Versão 2)
Agora nós queremos usar o prefixo somente para algumas keys, podemos usar um Pick no nosso Type ou fazer um novo generic.

- Passando um Pick
```ts
type PersonWithPrefix = WithPrefix<Pick<Person, 'name'>, 'person'>;
/* o retorno será:
type PersonWithPrefix = {
    personName: string;
}
*/
```

- Usando mais um generic
```ts
type WithPrefix<Type, Prefix extends string, Keys extends keyof Type = keyof Type> = {
    [Key in Keys as Key extends string ? `${Prefix}${Capitalize<Key>}` : Key]: Type[Key];
}

type Person = {
    name: string;
    age: number;
};

type PersonWithPrefix = WithPrefix<Person, 'person'>;

type JustPersonNameWithPrefix = WithPrefix<Person, 'person', 'name'>;
```

O que mudamos:
1. adicionar um generic Keys que é sempre uma key de Type (por isso o `extends keyof Type`)
2. demos um valor default para o novo generic. Quando não passamos valor algum isso irá assumir todas as keys de Type (por isso a expressão `= keyof Type`)
3. Por fim passamos a percorrer nosso loop usando Keys e o fluxo segue o mesmo

O retorno disso (se vc passar o mouse em cima dos dois ultimos types que criamos no seu vscode):
```ts
type PersonWithPrefix = {
    personName: string;
    personAge: number;
}

type JustPersonNameWithPrefix = {
    personName: string;
}
```

# Conclusão
Com isso pudemos ver mais sobre generics, como criar nosso próprio util type, como passar um default para um generic e como percorrer keys de um type, além de dar um novo "nomezinho" pra essa key.
Lembre-se de usar com cuidado e sempre prezando pela simplicidade no seu código. 

Afinal vc não coda somente para vc mesmo, mas sim para toda a sua equipe.