Como Criar Componentes Tipados no React Usando TypeScript

18/09/2024

Por Que Usar TypeScript com React?

Usar TypeScript com React oferece tipagem estática que ajuda a garantir que os componentes recebam e manipulem os dados corretamente, resultando em código mais seguro, legível e fácil de manter. Com a tipagem de props, estados e eventos, o TypeScript oferece um feedback mais rápido durante o desenvolvimento, prevenindo erros que, de outra forma, só seriam detectados em tempo de execução.

Configurando React com TypeScript

Antes de começar a criar componentes tipados, precisamos configurar um projeto React com TypeScript. Siga os passos abaixo para configurar o ambiente.

1. Criando um Projeto React com TypeScript

Execute o seguinte comando no terminal para criar um novo projeto React com TypeScript:

npx create-react-app meu-projeto --template typescript

Esse comando cria um projeto React com TypeScript pré-configurado. Ele inclui todas as dependências necessárias para começar a escrever componentes tipados.

Criando Componentes Tipados

Em React, podemos criar dois tipos principais de componentes: funcionais e de classe. A seguir, veremos como tipar ambos usando TypeScript.

1. Componentes Funcionais com Tipagem de Props

Os componentes funcionais são amplamente usados em React. Para tipá-los corretamente, devemos definir a interface das props que o componente receberá.

Exemplo de Componente Funcional Tipado

Vamos criar um componente funcional que exibe uma saudação baseada nas props recebidas. Crie o arquivo Saudacao.tsx com o seguinte código:

import React from 'react';

interface SaudacaoProps {
  nome: string;
}

const Saudacao: React.FC<SaudacaoProps> = ({ nome }) => {
  return <h1>Olá, {nome}!</h1>;
};

export default Saudacao;

Neste exemplo, usamos a interface SaudacaoProps para definir que o componente Saudacao espera uma prop nome do tipo string. O TypeScript garante que o componente só possa ser usado se o nome for passado corretamente como uma string.

2. Tipagem para Props Opcionais

Você pode definir props como opcionais, adicionando um ponto de interrogação ? na interface. Veja um exemplo de como fazer isso:

interface SaudacaoProps {
  nome?: string;
}

const Saudacao: React.FC<SaudacaoProps> = ({ nome = 'Visitante' }) => {
  return <h1>Olá, {nome}!</h1>;
};

Neste exemplo, a prop nome é opcional, e se não for fornecida, o componente exibirá "Visitante" por padrão. Isso garante mais flexibilidade no uso do componente.

Tipando Estado com Hooks

Além de props, você também pode tipar o estado em componentes funcionais ao usar useState. O TypeScript permite definir o tipo do estado, garantindo que o valor e a atualização sigam o tipo esperado.

Exemplo de Uso do useState com Tipagem

Vamos criar um componente que usa o hook useState para gerenciar um contador:

import React, { useState } from 'react';

const Contador: React.FC = () => {
  const [contador, setContador] = useState<number>(0);

  return (
    <div>
      <p>Contador: {contador}</p>
      <button onClick={() => setContador(contador + 1)}>Incrementar</button>
    </div>
  );
};

export default Contador;

Aqui, definimos explicitamente o tipo do estado contador como number ao usar o useState. Isso garante que apenas números possam ser atribuídos ao estado.

Tipando Eventos em Componentes React

Outro aspecto importante ao usar TypeScript com React é a tipagem de eventos, como cliques, mudanças em campos de entrada e submissões de formulários. O TypeScript fornece tipos específicos para esses eventos, o que facilita o trabalho com eles de maneira segura.

Exemplo de Tipagem de Eventos de Clique

import React from 'react';

const Botao: React.FC = () => {
  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
    console.log('Botão clicado!', event);
  };

  return <button onClick={handleClick}>Clique aqui</button>;
};

export default Botao;

Neste exemplo, estamos usando o tipo React.MouseEvent<HTMLButtonElement> para garantir que o evento seja corretamente tipado como um clique em um elemento button.

Exemplo de Tipagem de Eventos de Formulário

Você também pode tipar eventos de formulário. Veja um exemplo com um campo de entrada:

import React, { useState } from 'react';

const Formulario: React.FC = () => {
  const [nome, setNome] = useState<string>('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setNome(event.target.value);
  };

  return (
    <div>
      <input type="text" value={nome} onChange={handleChange} />
      <p>Nome: {nome}</p>
    </div>
  );
};

export default Formulario;

Usamos o tipo React.ChangeEvent<HTMLInputElement> para garantir que o evento de mudança de valor seja corretamente tipado como proveniente de um input HTML.

Criando Componentes de Classe Tipados

Embora os componentes funcionais sejam mais populares hoje em dia, você pode precisar usar componentes de classe, especialmente em projetos legados. O TypeScript também permite tipar facilmente componentes de classe.

Exemplo de Componente de Classe com Tipagem de Props e Estado

Vamos criar um componente de classe que exibe e incrementa um contador:

import React, { Component } from 'react';

interface ContadorProps {
  incremento: number;
}

interface ContadorState {
  valor: number;
}

class ContadorClasse extends Component<ContadorProps, ContadorState> {
  constructor(props: ContadorProps) {
    super(props);
    this.state = {
      valor: 0
    };
  }

  incrementar = () => {
    this.setState({ valor: this.state.valor + this.props.incremento });
  };

  render() {
    return (
      <div>
        <p>Valor: {this.state.valor}</p>
        <button onClick={this.incrementar}>Incrementar</button>
      </div>
    );
  }
}

export default ContadorClasse;

Neste exemplo, usamos as interfaces ContadorProps e ContadorState para tipar as props e o estado do componente. Isso garante que o incremento recebido como prop seja do tipo number, e que o estado valor seja tratado corretamente.

Boas Práticas ao Usar TypeScript com React

  • Use interfaces para props e estados: Sempre defina interfaces para garantir que as props e estados sejam corretamente tipados.
  • Tipagem explícita para useState: Ao usar o hook useState, defina explicitamente o tipo de estado, principalmente quando ele pode começar como null ou ser atualizado para outro tipo.
  • Evite any: Usar any derrota o propósito da tipagem estática. Prefira sempre definir o tipo correto para props, estados e eventos.
  • Organize suas interfaces: Mantenha as interfaces para props e estados em arquivos separados ou dentro do mesmo arquivo, mas sempre próximas ao componente que as utiliza.

Conclusão

Combinar React com TypeScript permite criar componentes robustos, seguros e fáceis de manter. A tipagem estática ajuda a evitar erros comuns relacionados a props e estados, além de melhorar a clareza do código. Usar TypeScript em projetos React traz uma camada extra de segurança durante o desenvolvimento, garantindo que a aplicação funcione conforme o esperado e seja mais fácil de escalar e refatorar no futuro.