Como usar o typescript a seu favor? (Parte 1)
Tags: typescript, programming, tutorial, opensource
Published: 2022-02-07 23:26:14

## Faça uso dos tipos base


Muitas vezes vemos as pessoas usando tipos primitivos, mas se esquecendo de criar os `tipos base` ou criando novos tipos sem necessidade.


Por exemplo:


```ts
type Person = {
 id: string;
 name: string;
 age: number
}


const getName = (id: string): Person => {
  // ...
}
```
Qual o problema do código acima? O tipo do parâmetro.


Por quê? Bom… basicamente se alguém, algum dia resolver mudar o tipo de `id` para `number` você terá de alterar em todos os lugares que fazem uso disso, sendo que, o typescript não irá te avisar, já que foi usado um tipo primitivo `string` em id. Para resolver esse problema, podemos fazer isso:
```ts
const getName = (id: Person['id']): Person => {
  // ...
}


// ou


const getName2 = ({ id }: Pick): Person => {
  // ...
}
```


Note que se você alterar o nome do atributo ou o tipo dele o typescript irá te avisar, porque faz referência ao tipo base `Person`. Além disso, você terá apenas um lugar para trocar essas informações. Obviamente, corrigindo os erros que serão detectados pelo typescript.


Os tipos base também podem te ajudar em componentes ou funções que precisam de "algo a mais". Pense no seguinte cenário: você possui um component que precisa receber informações referentes a `Person` e outras propriedades que são customizadas. Quando usamos o intellisense do vscode, por exemplo, a vida fica muito mais fácil, pois sabemos exatamente o que precisamos sem ficar abrindo vários arquivos (tabs hell). Então vamos aos exemplos:


```ts
type Props = Person & {
  enabled?: boolean;
}


const Component = ({ enabled = false, name }: Props) => (
  {name}
)
```
Nesse cenário, quando você for usar o `Component` precisam ser passadas propriedades que você não precisa usar. Além disso, se o tipo `Person` for modificado, você precisará alterar todos os componentes para receberem a nova propriedade (pensa no trabalho tenso).


Sendo assim e muito mais "fácil" (menos trabalhoso no futuro) você criar o seu tipo Props dessa forma:


```ts
type Props = Pick<Person, 'id'> & {
  enabled?: boolean;
}
```


ou...


```ts
type Props = {
  id: Person['id'];
  enabled?: boolean;
}
```


Assim você não precisa se preocupar com mudanças em `Person`, porque seu component só usará `id` e caso o tipo de `id` vire um `number` o typescript ira te avisar em qual lugar irá quebrar (olha que coisa linda).


## Sempre que possível use os util types

Util types estão aí para facilitar nossa vida, pois você pode pegar exatamente o que necessita para passar em seus parâmetros ou até mesmo criar um tipo novo sem muito esforço, como mostrado no exemplo acima. Você pode inclusive mesclar vários (sempre com cuidado para não ficar complicado de ler).
Por exemplo:

```ts
type Person = {
  id: string;
  name: string;
  age: number;
}

type PersonFactory = {
  create: () => Person & {
    update: <Payload extends Partial<Omit<Person, 'id'>>>(payload: Payload) => Person
  }
}

const getRandomNumber = (min: number, max: number): number => {
  return Math.ceil(Math.random() * (max - min) + min)
}

const personFactory: PersonFactory = {
  create: () => ({
    id: `${Math.random()}`,
    name: `A name generated`,
    age: getRandomNumber(1, 100),
    update(params) {
      return {
        ...this,
        ...params
      }
    }
  })
}

const person = personFactory.create()

console.log(person.update({ name: 'Other name' }))

console.log(person.update({ id: '1' })) /* error: Object literal may only specify known properties, and 'id' does not exist in type 'Partial<Omit<Person, "id">>'.*/
```

Nesse exemplo nós temos uma função de update para cada pessoa gerada por nossa factory, porém com uma particularidade... o único atributo que nao e possivel editar e o `id`. Então usamos o util type `Omit` para garantir que o tipo payload passado como generic (veremos a seguir) só possua atributos de `Person` com exceção do `id`.

Caso voce esteja trabalhando com possiveis valores de `string`, por exemplo, e em algum momento deseja criar um tipo que só precisa de parte desses valores você pode usar o util type `Exclude` para te ajudar nessa tarefa.

```ts
type States = 'active' | 'pending' | 'done' | 'failed';

type CompletedStates = Exclude<States, 'active' | 'pending'>;
// 'done' | 'failed'
```

> Existem muitos outros util types, mas os mais comuns de se usar sao `Partial`, `Required`, `Pick`, `Omit`, `Exclude`. [Conheca os outros aqui](https://www.typescriptlang.org/docs/handbook/utility-types.html)