Typescript e sua utilização no React

18 de fevereiro, 2021 — 4 min read

Typescript e sua utilização no React

Typescript

Typescript é um supertset do JavaScript que adiciona tipos, algumas pessoas chamam de linguagem, mas não muda o fato que todo código em Javascript é um código válido em Typescript.

Tipagem

A tipagem é o que tornou o Typescript tão atraente. Javascript por ter tipagem dinâmica brilha os olhos de muitos devs, facilitando para iniciar na linguagem, mas quando caímos em casos mais complexos e bases de códigos maiores essa tipagem dinâmica acaba atrapalhando o entendimento do código e não trazendo confiabilidade.

Agora trazendo exemplos práticos, se tentarmos fazer algo como:

let firstName = 'André'

firstName = 0

Teremos o erro: Type 'number' is not assignable to type 'string'.(2322) mesmo não informando que a variável firstName é uma string o Typescript tem a inteligência de inferir o tipo, então quando tentamos reatribuir um number o compilador gera um erro de tipo trazendo mais confiabilidade pras variáveis.

Tipos complexos

Quando trabalhamos com Javascript é bem comum utilizarmos Arrays e Objetos. Para esses casos tem várias opções de tipagem, sendo as mais comuns a interface e os type aliases.

Utilizando o exemplo anterior é possível criar um type alises pra variável firstName informando que ela pode receber um número.

type NameOrYear = number | string

let firstName: NameOrYear = 'André'

firstName = 0

A declaração poderia ser diretamente let firstName: number | string = 'André' mas utilizando o type aliases a tipagem fica mais clara, organizada e pode ser reutilizada.

Agora falando da estrutura mais utilizada no Javascript que é o Objeto podemos utilizar as interfaces para ter uma confiabilidade do que esperamos na variável daquele tipo.

interface PersonalInfos {
  name: string
  age: number
  hobbies: Array<string>
}

const zagatti: PersonalInfos = {}

Antes de comentar mais sobre o código, devo fazer um parenteses para a declaração dos hobbies. Existem duas formas de declarar um array de tipos, sendo por exemplo string[] e como eu declarei Array<string>. Esse sinal de menor e maior signficam que o tipo Array espera um generics, que nada mais é que passar um tipo para ele saber como é a estrutura desse array, podendo receber outros tipos como uma interface que define um objeto.

Depois desse parenteses devo dizer que o código acima causará um erro( Type '{}' is missing the following properties from type 'PersonalInfos': name, age, hobbies(2739) ), pois o compilador do Typescript espera que a variável zagatti inicie com os campos informados com as tipagens corretas, ajustando a inicialização deveria ser algo como:

const zagatti: PersonalInfos = {
  name: 'André',
  age: 23,
  hobbies: ['Programar', 'Tomar café'],
}

Mas também existe uma forma de forçar a tipagem do objeto vazio(Type Assertion) utilizando a palavra as, então ficaria:

const zagatti: PersonalInfos = {} as PersonalInfos

Um ponto de atenção é utilizar essa afirmação de tipos com cuidado para acabar não tentando acessar valores que não existem e parecem existir por conta do Type Assertion.

Também temos como informar que alguns campos opcionais, e para isso declaramos o campo com ?:

interface PersonalInfos {
  name: string
  age?: number
  hobbies?: Array<string>
}

const zagatti: PersonalInfos = { name: 'André' }

Assim não teremos nenhum erro, pois o compilador entende que somente a chave name é esperada na inicialização da variável com o tipo PersonalInfos.

Acredito que consegui passar a maior parte das informações básicas de quando utilizamos Typescript, existe muito mais coisa dentro desse superset, uma feature que recomendo olharem são os Utility Types e toda a documentação dele.

Typescript no React

No React sempre buscamos a confiabilidade na hora de se passar props de um componente para outro, então por muito tempo utilizamos um pacote chamado prop-types, onde conseguiamos definir um tipo para as props que um componente recebe, mas a confiabilidade era somente os erros que aconteciam quando o projeto estava rodando, o Typescript foi além trazendo os erros na hora de desenvolver e também com a confiabilidade de tipos em states, funções externas e muito mais.

Imaginemos um componente que recebe um nome por prop, faz uma busca e traz o sobrenome e a idade dessa pessoa, em Javascript o componente seria algo como:

import { useEffect, useState } from 'react'

export const Main = ({ name, children }) => {
  const [data, setData] = useState()

  useEffect(() => {
    // api call
    setData({
      lastName: 'Zagatti',
      age: 23,
    })
  }, [])

  return (
    <div>
      <h1>{`${name} ${data?.lastName} - ${data?.age}`}</h1>
      {children}
    </div>
  )
}

Olhando assim pode parecer um pouco óbvio que name é uma string, children são as tags filhas do componente Main e o estado data tem um campo lastName e age, mas quando utilizamos o componente não é obrigatório passar a prop name causando um undefined na tela, podemos tratar com o operador || no h1 mas podem acontecer N problemas de pessoas não entenderem qual campo espera o que.

Agora o mesmo componente declarado com o Typescript ficaria:

import { ReactNode, useEffect, useState } from 'react'

interface Data {
  lastName: string
  age: number
}

interface MainProps {
  name: string
  children?: ReactNode
}

export const Main = ({ name, children }: MainProps) => {
  const [data, setData] = useState<Data>()

  useEffect(() => {
    // api call
    setData({
      lastName: 'Zagatti',
      age: 23,
    })
  }, [])

  return (
    <div>
      <h1>{`${name} ${data?.lastName} - ${data?.age}`}</h1>
      {children}
    </div>
  )
}

Hmm, mais verboso correto?! Talvez sim, mas muito mais claro e óbvio do que fazer com o componente, agora se utilizarmos o componente em outro arquivo .tsx e não passarmos a prop name teremos o erro de tipo Type '{}' is missing the following properties from type 'MainProps': name ts(2739) o que é maravilhoso, sabemos que pro componente funcionar como foi feito precisamos passar as props corretas, além de termos a inteligência no desenvolvimento, o tão conhecido IntelliSense.

Tudo o que mostrei antes do Typescript também se aplica ao contexto do React, ou seja, se tentar atribuir um objeto com campos diferentes para o estado data vai acontecer um erro de tipos. Além do useState existem muitas outras utilizações do Typescript com partes do React, como por exemplo esse componente de Input:

import { ComponentType, InputHTMLAttributes } from 'react'
import { IconBaseProps } from 'react-icons'

import { Container } from './styles'

interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
  isErrored?: boolean
  icon?: ComponentType<IconBaseProps>
}

export const Input = ({
  isErrored,
  icon: Icon,
  children,
  className,
  name,
  ...rest
}: InputProps) => {
  return (
    <Container className={className} isErrored={isErrored}>
      {Icon && <Icon size={20} />}
      {children}
      {!children && (
        <label htmlFor={name}>
          <input name={name} {...rest} />
        </label>
      )}
    </Container>
  )
}

Pode parecer complexo de início mas uma interface pode extender uma já existente que nesse caso são os atributos da tag input. Com o Typescript temos essa confiança de criar componentes complexos e termos a certeza que todos os dados estão de acordo com seus tipos, como por exemplo a prop Icon que é um componente de ícone da biblioteca ‘react-icons’.

Conclusão

No final desse post só posso dizer que existe um mundo muito maior em torno do Typescript e da sua utilização no mundo do frontend, e no exemplo passado no React.

Recomendo utilizarem o Typescript o máximo que conseguirem, chega um momento que se torna natural trabalhar com essa ferramenta e não existe nenhum motivo de não se utilizar das features que esse superset fornece, uma hora ou outra acaba aparecendo um edge case no projeto que seria ótimo se um sistema de tipos estivesse disponível nele.


Se inscreva para novidades:

Para mais informações, acesse:Política de Privacidade

Enviar
A. Zagatti Logo

André Zagatti

Engenheiro de software frontend que gosta de compartilhar conhecimento.

© 2023, André Zagatti