Tipos Especiais com Typescript

Tipos especiais com Typescript

Você sabia que podemos fazer o uso de alguns tipos especiais, como:

  • Enum
  • Types

Dentro de nossas aplicações feitas com React? Quer saber como isso é feito?

Então fique até o final desta lição e descubra 😉

Usando Enums

Como você já sabe, um Enum nada mais é do que um meio que nós temos de formatar nossos objetos, por meio chaves e valores. 

No ReactTS, você pode passar uma determinada chave para um componente usando uma prop, para que futuramente você possa imprimir (ou processar) o valor dela dentro do componente.

No caso dos Enum, como recomendação, eu sugiro que você crie eles dentro de uma pasta chamada enums, mais especificamente dentro da pasta src do seu projeto:

Isso vai ao encontro às boas práticas de organização por funcionalidade, que a propósito, você já aprendeu na jornada ReactJS 😋

Feito isso, vamos ver um exemplo bem simples da utilização de um Enum.

Dentro da pasta enums (que você acabou de criar), vamos criar um novo arquivo chamado de StatusEnum.ts, que será um arquivo responsável por definir um enum, para os diferentes estados que um componente pode assumir.

enums > StateEnum.ts:

export enum Status {
  Success = 'Success',
  Warning = 'Warning',
  Error = 'Error',
}

Em seguida, vamos criar o nosso componente chamado de StatusBadge, que representa um componente simples que faz o uso do nosso Enum para mostrar uma mensagem personalizada.

components > StatusBadge.tsx:

import React from 'react';
import { Status } from '../enums/StateEnum';

// Define o tipo para as props do componente
interface StatusBadgeProps {
  status: Status;
}

// Define as cores para cada status
const statusColors: Record<Status, string> = {
  [Status.Success]: 'green',
  [Status.Warning]: 'yellow',
  [Status.Error]: 'red',
};

// Componente StatusBadge
const StatusBadge: React.FC<StatusBadgeProps> = ({ status }) => {
  return (
    <span
      style={{
        padding: '0.5em 1em',
        borderRadius: '4px',
        backgroundColor: statusColors[status],
        color: 'white',
        fontWeight: 'bold',
      }}
    >
      {status}
    </span>
  );
};

export default StatusBadge;

Para utilizar esse componente, basta que você passe via props seus Enums da seguinte forma:

import StatusBadge from './components/StatusBadge';
import { Status } from './enums/StatusEnum';

....

<StatusBadge status={Status.Success} />
<StatusBadge status={Status.Warning} />
<StatusBadge status={Status.Error} />

Vejamos agora, uma explicação um pouco mais detalhada de tudo o que aconteceu nos códigos anteriores.

Enum: Definimos um enum Status para os diferentes estados possíveis (Success, Warning, Error).

StatusBadge Component: O componente StatusBadge recebe uma prop status do tipo Status. Ele usa essa prop para definir a cor de fundo do badge com base no enum.

statusColors: Um objeto statusColors é usado para mapear cada status para uma cor específica.

Utilização: No componente escolhida, você pode utilizar o componente StatusBadge passando diferentes valores do enum para demonstrar diferentes estados.

Com a utilização de Enums no ReactTS, você pode ter um código mais legível e menos propenso a erros.

Criando um Enum de Nomes

Para fixar ainda mais o conceito de Enums, vamos criar um novo Enum chamado de NomesEnum.

enums > NomesEnum.ts:

export enum NomesEnum {
  Alice = 'Alice Journeys Linch',
  Bob = 'Bob Cinclair',
  Charlie = 'Charlie Downtown Niltur',
}

O código acima representa um enumerado, onde armazenamos os nomes de três pessoas diferentes.

A ideia é que o nosso componente possa receber a chave Alice, Bob ou Charlie, e com isso, consiga ter acesso ao nome completo da pessoa.

Agora, chegou a hora de criar o nosso componente que vai fazer o uso desse Enum:

components > MostraNome.tsx:

import React from 'react';
import { NomesEnum } from '../enums/NomesEnum';

const MostraNome: React.FC<{ nome: NomesEnum }> = ({ nome }) => {
  return <h1>{nome}</h1>;
};

export default MostraNome;

Note que recebemos o enumerado que acabamos de criar (NomesEnum), e por meio da chave, estamos mostrando o valor armazenado dentro daquele enumerado.

Para usar o componente MostraNome é bem simples, observe:

import MostraNome from './MostraNome';
import { NomesEnum } from './NomesEnum';

....

<MostraNome nome={NomesEnum.Alice} />
<MostraNome nome={NomesEnum.Bob} />
<MostraNome nome={NomesEnum.Charlie} />

Ficou mais claro que o uso dos Enums faz com que os dados trafegados dentro dos nossos componentes, se tornem cada vez mais legíveis e esperados?

Essa é a grande sacada dessa funcionalidade, pois dessa forma, conseguimos padronizar a nível de objeto, os dados que estamos recebendo.

Apesar do código acima funcionar tranquilamente, a utilização de Enums costuma ser bastante utilizada em conjunto com as interfaces.

Observe um outro exemplo do mesmo componente MostraNome, só que dessa vez trabalhando com Enums + Interfaces:

components > MostraNome.tsx:  

import React from 'react';
import { NomesEnum } from './NomesEnum';

// Define o tipo para as props do componente
interface MostraNomeProps {
  nome: NomesEnum;
}

const MostraNome: React.FC<NomeDisplayProps> = ({ nome }) => {
  return <h1>{nome}</h1>;
};

export default MostraNome;

Enums sem Interface: No exemplo sem a interface, o tipo das props é definido diretamente no componente como um tipo inline ({ nome: NomesEnum }). Isso funciona muito bem para os casos mais simples, mas pode ser menos claro e menos flexível do que usar uma interface, especialmente à medida que o componente se torna mais complexo.

Enums com Interface: Usar uma interface (MostraNomeProps) é útil para definir claramente a estrutura das props, facilitando a leitura e a manutenção do código, além de proporcionar melhores mensagens de erro, e também autocompletar as ferramentas de desenvolvimento.

Para componentes simples, você pode optar por definir o tipo inline (enums sem interface), mas para projetos maiores ou componentes mais complexos, é recomendado usar enums em conjunto com interfaces para definir suas props.

Usando Types

No momento, nós aprendemos a criar estruturas de tipo usando Interfaces, mas você sabia que nós também podemos usufruir das Types?

Será por meio das Types que nós conseguiremos criar dados com uma tipagem mais fixada, ou seja, tipos de dados fixos. Vamos ver na prática como podemos aplicar esse conceito no React 

Para começarmos, vamos criar um componente que vai possuir um Type que aceita somente dois tipos de valores: string ou null.

components > ExemploTypes.tsx:

type textoOuNulo = string | null;

const ExemploTypes = () =>  {
  const nome:textoOuNulo = null;
  const sobrenome:textoOuNulo = "Roll";
  const numero:textoOuNulo = 2; //O TS vai gerar uma mensagem de erro, pois só pode ser string ou null, e não um number

  return nome + sobrenome;
}

export default ExemploTypes;

No caso do exemplo acima, criamos um Type chamado de textoOuNulo, que é um tipo que pode receber apenas dois valores: string ou null.

Note que a partir do momento em que tentamos atribuir qualquer outro tipo de valor que não seja uma string ou um null, o Typescript gera um erro no console:

const numero:textoOuNulo = 2; //O TS vai gerar uma mensagem de erro, pois só pode ser string ou null, e não um number

Vejamos um outro exemplo em que criamos valores pré-fixados:

components > ExemploTypes.tsx:  

type textoOuNulo = string | null;
type fixado = "Sucesso" | "Alerta" | "Perigo";

const ExemploTypes = () =>  {
  const nome:textoOuNulo = null;
  const sobrenome:textoOuNulo = "Roll";
  const numero:textoOuNulo = 2; //O TS vai gerar uma mensagem de erro, pois só pode ser string ou null, e não um number

  const mensagemUm:fixado = "Sucesso";
  const mensagemDois:fixado = "Perigo";
  const mensagemTres:fixado = "Micilini Roll";//O TS vai gerar uma mensagem de erro, pois os valores aceitos são apenas "Sucesso, Alerta e Perigo".

  return nome + sobrenome;
}

export default ExemploTypes;

No código acima, nós criamos um tipo chamado de fixado, que só pode receber 3 tipos de dados do tipo string: Sucesso, Alerta e Perigo.

Qualquer outro tipo de dado, mesmo que ela seja uma string, vai gerar um erro no Typescript:

const mensagemTres:fixado = "Micilini Roll";//O TS vai gerar uma mensagem de erro, pois os valores aceitos são apenas "Sucesso, Alerta e Perigo".
const mensagemQuatro: fixado = 11;//O TS vai gerar uma mensagem de erro, pois só aceita strings...

Agora, caso você queira fazer com que um determinado Type, atue como se fosse uma Interface, você pode fazer isso da seguinte forma:

components > Informacoes.tsx:

import React from 'react';

// Definição do tipo para as props dentro do mesmo arquivo
type InformacoesProps = {
  nome: string;
  idade: number;
  email: string;
};

const Informacoes: React.FC<InformacoesProps> = ({ nome, idade, email }) => {
  return (
    <div>
      <h1>Informações</h1>
      <p><strong>Nome:</strong> {nome}</p>
      <p><strong>Idade:</strong> {idade}</p>
      <p><strong>Email:</strong> {email}</p>
    </div>
  );
};

export default Informacoes;

Note que criamos um novo type chamado de InformacoesProps, que fica responsável por definir todas as propriedades que o nosso componente (Informacoes) vai receber.

Arquivos da lição

Os arquivos desta lição podem ser encontrados no repositório do GitHub por meio deste link.

Conclusão

Nesta lição, você aprendeu a usar os tipos especiais (Enum e Type) no ReactTS.

Até a próxima lição 😃

Criadores de Conteúdo

Foto do William Lima
William Lima
Fundador da Micilini

Inventor nato, escreve conteudos de programação para o portal da micilini.

Torne-se um MIC 🤖

Mais de 100 mic's já estão conectados na plataforma.