ProgramaçãoTypeScript

Como Tipar da Forma Correta com TypeScript

O TypeScript tem ganhado popularidade por oferecer recursos avançados, como tipagem estática, que proporcionam um desenvolvimento mais seguro e eficiente. Neste artigo, vamos aprender a tipar de forma correta, explorando seus recursos e fornecendo exemplos práticos para ilustrar como ele pode elevar a qualidade do seu código.

Tipagem com TypeScript
Tipagem com TypeScript.

Acesse também: Melhores Práticas com HTML Semântico para um Código Limpo

Configuração do TypeScript

Antes de aprender a tipar, vamos criar e entender o arquivo de configuração do typescript, o arquivo tsconfig.json. Este arquivo contém as opções de configuração que definem como o TypeScript compilará seu código.

1. target:

A opção target define para qual versão do ECMAScript o TypeScript compilará. Escolher uma versão mais recente permite o uso de recursos modernos do JavaScript.

   "compilerOptions": {
     "target": "es6",
   }

2. module:

A opção module especifica o sistema de módulos a ser usado. Para projetos Node.js, commonjs é uma escolha comum.

   "compilerOptions": {
     "module": "commonjs", // pode ser utilizado outros modulos como o 'esnext' para aplicações Next.JS
   }

3. strict:

Ativar strict é altamente recomendado, pois habilita várias opções de checagem de tipo rigorosas que tornam o código mais seguro.

   "compilerOptions": {
     "strict": true,
   }

4. outDir e rootDir:

Essas opções determinam onde os arquivos compilados serão colocados (outDir) e onde o TypeScript procurará seus arquivos (rootDir).

   "compilerOptions": {
     "outDir": "./dist",
     "rootDir": "./src",
   }

5. esModuleInterop:

Para garantir uma interoperabilidade suave entre módulos CommonJS e ES6, você pode ativar esModuleInterop.

   "compilerOptions": {
     "esModuleInterop": true,
   }

6. strictNullChecks:

Essa opção aperta as regras em torno de valores null e undefined, ajudando a evitar erros comuns.

   "compilerOptions": {
     "strictNullChecks": true,
   }

7. Configuração Completa do TypeScript:

Aqui está um exemplo da configuração completa do TypeScript (no arquivo tsconfig.json) com várias opções configuradas que você pode usar no seu projeto:

   {
     "compilerOptions": {
       "target": "es6",
       "module": "commonjs",
       "strict": true,
       "outDir": "./dist",
       "rootDir": "./src",
       "esModuleInterop": true,
       "strictNullChecks": true
     }
   }

Ao configurar essas opções, você está adaptando o ambiente para atender às especificidades do seu projeto. Essa configuração é um equilíbrio entre segurança de tipo e flexibilidade, garantindo que você tenha um ambiente de desenvolvimento poderoso e adaptado às suas necessidades.

Tipagem Estática em Ação

1. Tipos Básicos:

TypeScript oferece uma variedade de tipos básicos, incluindo number, string, boolean, array, tuple, enum e any. Vamos ver alguns exemplos:

   // Números
   let idade: number = 25;

   // Texto
   let nome: string = "João";

   // Booleano
   let ativo: boolean = true;

   // Array
   let numeros: number[] = [1, 2, 3];

   // Tupla
   let coordenadas: [number, number] = [10, 20];

   // Enum
   enum DiaDaSemana {
     Segunda,
     Terca,
     Quarta,
     Quinta,
     Sexta,
     Sabado,
     Domingo,
   }

   let hoje: DiaDaSemana = DiaDaSemana.Sexta;

   // Qualquer tipo (evitar seu uso quando possível)
   let variavelQualquer: any = "qualquer coisa";

2. Funções com Tipos:

Ao criar funções, você pode especificar os tipos dos parâmetros e do retorno.

   function somar(a: number, b: number): number {
     return a + b;
   }

   function saudacao(nome: string): string {
     return `Olá, ${nome}!`;
   }

Observe que a função somar está tipada para receber um ‘a‘ e um ‘b‘ que são números, e irá retornar um número também.

3. Interfaces e Tipos Personalizados:

Use interfaces para definir a forma de um objeto e tipos personalizados para criar combinações complexas de tipos.

   // Interface
   interface Usuario {
     nome: string;
     idade: number;
   }

   function mostrarUsuario(usuario: Usuario): void {
     console.log(`Nome: ${usuario.nome}, Idade: ${usuario.idade}`);
   }

   // Tipo Personalizado
   type Coordenada = [number, number];

   function mostrarCoordenada(coordenada: Coordenada): void {
     console.log(`Latitude: ${coordenada[0]}, Longitude: ${coordenada[1]}`);
   }

Interfaces é a forma mais profissional de fazer tipagem quando uma função recebe vários parâmetros como argumento.

TypeScript Intermediário

1. Classes e Herança:

TypeScript permite uma programação orientada a objetos mais robusta com suporte a classes e herança.

   class Animal {
     constructor(public nome: string) {}

     fazerBarulho(): void {
       console.log("Algum barulho genérico");
     }
   }

   class Cachorro extends Animal {
     fazerBarulho(): void {
       console.log("Au au!");
     }
   }

   const meuCachorro = new Cachorro("Bolt");
   meuCachorro.fazerBarulho(); // Saída: Au au!

2. Genéricos:

Genéricos <T> oferecem uma maneira de escrever código flexível que pode funcionar com diferentes tipos de dados.

   function obterElementoAleatorio<T>(lista: T[]): T {
     const indiceAleatorio = Math.floor(Math.random() * lista.length);
     return lista[indiceAleatorio];
   }

   const elementoAleatorio = obterElementoAleatorio(["Maçã", "Banana", "Laranja"]);
   console.log(elementoAleatorio); // Saída: Pode ser Maçã, Banana ou Laranja

3. Promises e Async/Await:

TypeScript facilita o uso de promessas e async/await para lidar com operações assíncronas.

   function aguardarTempo(ms: number): Promise<void> {
     return new Promise((resolve) => setTimeout(resolve, ms));
   }

   async function exemploAsync(): Promise<void> {
     console.log("Início da execução");
     await aguardarTempo(2000);
     console.log("Execução após 2 segundos");
   }

   exemploAsync();

Uma boa prática em Promises e Async/Await é tipar elas com uma interface, como no exemplo abaixo.


   // Interface
   interface Usuario {
     ms: number;
   }

   function aguardarTempo({ ms }: Usuario): Promise<void> {
     return new Promise((resolve) => setTimeout(resolve, ms));
   }

TypeScript Avançado

1. Decoradores:

Decoradores são uma característica avançada do TypeScript que permite modificar ou estender a funcionalidade de classes, métodos, propriedades e acessores. Eles são comumente usados em conjunto com bibliotecas como Angular.

   function logarClasse(construtor: Function) {
     console.log(`Registrando a classe: ${construtor}`);
   }

   @logarClasse
   class ExemploDecorador {
     // Conteúdo da classe...
   }

Quando a classe ExemploDecorador é definida e marcada com @logarClasse, o TypeScript automaticamente chama a função logarClasse com o construtor da classe como argumento. Portanto, o que quer que esteja dentro da função logarClasse será executado quando a classe for definida.

2. Tipos Condicionais:

Tipos condicionais permitem criar tipos que dependem de uma condição. Isso é particularmente útil ao lidar com tipos de dados dinâmicos.

   type ExcluirPropriedade<T, K extends keyof T> = {
     [P in keyof T as P extends K ? never : P]: T[P];
   };

   interface Usuario {
     id: number;
     nome: string;
     email: string;
   }

   type UsuarioSemId = ExcluirPropriedade<Usuario, 'id'>;
   // Resultado: { nome: string; email: string }
  • ExcluirPropriedade<T, K extends keyof T>: Aceita dois parâmetros genéricos: T (um tipo) e K (uma chave desse tipo T).
  • [P in keyof T as P extends K ? never : P]: T[P]: Este é um tipo mapeado. Ele itera sobre todas as propriedades P do tipo T. A parte mais complexa está na expressão condicional P extends K ? never : P. Isso significa que, se P for uma subchave de K (ou seja, P extends K), então ela é mapeada para never (um tipo que significa ausência de valor), caso contrário, ela é mantida como P.

3. Integração com Webpack:

Integração do TypeScript com Webpack é crucial para projetos mais complexos. Configurar o Webpack para compilar arquivos TypeScript e lidar com módulos é uma habilidade essencial.

   // Arquivo webpack.config.js
   const path = require('path');

   module.exports = {
     entry: './src/index.ts',
     output: {
       filename: 'bundle.js',
       path: path.resolve(__dirname, 'dist'),
     },
     resolve: {
       extensions: ['.ts', '.js'],
     },
     module: {
       rules: [
         {
           test: /\.ts$/,
           use: 'ts-loader',
           exclude: /node_modules/,
         },
       ],
     },
   };

4. Ambientes de Testes com Jest:

Para garantir a qualidade do código, é essencial ter testes automatizados. Integrar o TypeScript com o Jest simplifica a escrita de testes e garante uma cobertura abrangente.

   // Arquivo jest.config.js
   module.exports = {
     preset: 'ts-jest',
     testEnvironment: 'node',
   };

5. Mixins e Herança Múltipla:

Embora o JavaScript não suporte herança múltipla tradicional, você pode implementar padrões de design de mixins para obter funcionalidades compartilhadas em várias classes.

   class SalvarMixin {
     salvar() {
       console.log('Salvando...');
     }
   }

   class ValidarMixin {
     validar() {
       console.log('Validando...');
     }
   }

   interface Usuario extends SalvarMixin, ValidarMixin {
     nome: string;
     email: string;
   }

Use o TypeScript Sempre em Seus Projetos

O TypeScript oferece uma experiência de desenvolvimento web mais robusta, fornecendo tipagem estática, interfaces, genéricos e mais. Esses recursos não apenas tornam o código mais seguro, mas também melhoram a eficiência e a legibilidade. Ao adotar o TypeScript, você estará capacitando sua equipe a escrever código mais confiável e escalável, contribuindo para o sucesso de projetos web modernos.

Deixe uma reação

Engraçado
0
Feliz
0
Amei
0
Interessante
0

You may also like

Leave a reply

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *