DEV Community

Mat
Mat

Posted on • Edited on

Como usar o typescript a seu favor? (Parte 1)

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:

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


const getName = (id: string): Person => {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

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:

const getName = (id: Person['id']): Person => {
  // ...
}


// ou


const getName2 = ({ id }: Pick): Person => {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

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:

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


const Component = ({ enabled = false, name }: Props) => (
  {name}
)
Enter fullscreen mode Exit fullscreen mode

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:

type Props = Pick<Person, 'id'> & {
  enabled?: boolean;
}
Enter fullscreen mode Exit fullscreen mode

ou...

type Props = {
  id: Person['id'];
  enabled?: boolean;
}
Enter fullscreen mode Exit fullscreen mode

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:

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">>'.*/
Enter fullscreen mode Exit fullscreen mode

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.

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

type CompletedStates = Exclude<States, 'active' | 'pending'>;
// 'done' | 'failed'
Enter fullscreen mode Exit fullscreen mode

Existem muitos outros util types, mas os mais comuns de se usar sao Partial, Required, Pick, Omit, Exclude. Conheca os outros aqui

Top comments (0)