Como (e por que) utilizar o TypeScript em seus projetos futuros
Como (e por que) utilizar o TypeScript em seus projetos futuros
Por Jhonatan Gonçalves • Publicado em 01/08/2022
Salvar
Como (e por que) utilizar o TypeScript em seus projetos futuros. Entenda de maneira rápida as vantagens, e como colocar o desenvolvimento em prática.

Introdução

Há alguns anos, quando softwares para desktop eram desenvolvidos em larga escala e a demanda era alta, as linguagens tipadas dominavam o mercado.

Com a popularização da internet, e o desenvolvimento web se tornando mais presente, linguagens como o JavaScript se tornavam mais populares com o passar dos anos. A dinâmica do desenvolvimento era fascinante, porque com poucas linhas e praticamente nenhuma tipagem era possível fazer quase qualquer coisa. E em termos de produtividade, parecia ser um ambiente perfeito.

Então, se a mudança foi realmente para melhor, por que o TypeScript está se tornando tão popular? E a cada dia que passa, mais desenvolvedores estão incorporando-o em seus projetos, frameworks estão sendo migradas, e muitas outras funcionalidades estão sendo aplicadas neste universo. Seria isso um passo atrás, ou um avanço?

Em termos gerais, podemos considerar um avanço, mas a sua aplicabilidade depende do propósito. Para um projeto pessoal, ou apenas um esboço rápido, sua utilização pode parecer desnecessária, e as suas vantagens podem parecer não trazer tantos benefícios assim. Porem, quando se trata de projetos mais complexos onde equipes trabalham em conjunto, seus benefícios são percebidos consideravelmente.

Por que usar o TypeScript?

Basicamente, o TypeScript oferece todos os recursos do JavaScript e uma camada adicional, o seu sistema de tipos. Em poucas palavras, um JavaScript tipado. É claro que esta é uma descrição simples para um entendimento rápido, e tudo o que ele tem a oferecer nos permitiria aprofundar em seus conceitos.

Logo abaixo, nos aprofundaremos mais nestas ideias. Mas caso queira um material complementar para aprofundar-se, recomendo a leitura da visão geral no site oficial: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html.

Produtividade

O termo produtividade por si só já é bastante controverso. Mas, sigamos, se produtividade for iniciar o desenvolvimento de maneira rápida, e em poucos minutos já estarmos desenvolvendo nossas primeiras linhas de código, e sem termos que nos preocupar com implementações extras, como criação de interfaces ou tipos específicos. Com certeza, o JavaScript puro nos dá uma produtividade muito boa.

Quando elevamos a produtividade para um contexto mais amplo, de longo prazo, escalável, e com aumento de equipe, a história muda. A manutenção do projeto também entra em cena. Esta que é uma parte do processo de desenvolvimento que acompanhará o projeto por toda a sua vida útil. E é aí que entra o TypeScript.

Tipagem segura e a diminuição dos erros

Quando definimos explicitamente os tipos dos valores, como por exemplo as interfaces dos objetos e o retorno dos métodos, possibilitamos uma identificação mais rápida, e prática, dos erros que seriam levantados por algum descuido. Erros que seriam percebidos apenas em tempo de execução, e muitas vezes, difíceis de serem identificados. 

Um exemplo de tipagem e apresentação de erro durante o desenvolvimento:

Simulação do erro de tipagem
Simulação do erro de tipagem

Na linha 5: estamos tentando passar um valor do tipo string para um método que recebe como parâmetro um valor do tipo numérico.

Na linha 7: estamos tentando armazenar um valor numérico, retornado do método, em uma constante do tipo string.

Um exemplo de criação de interface com definição dos atributos padrões:

Simulação do erro de interface com atribuição de propriedade não definida.
Simulação do erro de interface com atribuição de propriedade não definida.

No exemplo anterior, criamos um objeto user com um campo não mapeado na interface, username, e que provavelmente não será utilizado internamente. O que ocasionou o hint de erro na aplicação.

Erros que poderiam facilmente passar despercebidos num projeto sem as devidas configurações.

Exposição clara dos módulos do projeto

Conforme o projeto cresce, o número de módulos, diretórios e classes aumenta significativamente. Quando trabalhamos com o TypeScript, o controle se torna menos árduo e temos uma noção mais ampla do projeto como um todo. Um ponto positivo é que as ferramentas de desenvolvimento também trabalham melhor com a exposição das classes, atributos e métodos permitindo uma navegação fácil, e identificação de seus tipos.

Navegação entre classes através de todo o projeto, dando uma identificação inicial, e ao clicar para navegar (ir), nos permite acessar diretamente a declaração do que estamos selecionando.

Um autocomplete mais assertivo dos recursos importados de outros arquivos. Como demonstra no exemplo a seguir, os atributos de uma instância de User.

Arquivos de declaração de tipos - Type Declaration files (d.ts)

Primeiramente, precisamos entender que os arquivos de declaração de tipos se fazem necessário devido ao código final, o que irá ser executado em produção ou disponibilizado como plugin, ser transformado em JavaScript puro após compilação. Ou seja, trabalhamos com o TypeScript na fase de desenvolvimento, porém quando fizermos a release, o código disponibilizado será JavaScript.

Também é possível criar arquivos d.ts para projetos que foram criados em JavaScript puro, para prover melhor compatibilidade com projetos em TypeScript, caso seja um plugin.

Um arquivo de declaração de tipos, como o próprio nome sugere, é um arquivo que contem apenas a declaração dos tipos do projeto, e não há regra de negócios propriamente dita. É utilizado apenas para propósitos de desenvolvimento, e prover informações que facilitem o desenvolvimento.

Um exemplo prático, e bastante utilizado, é o fornecimento desses arquivos em conjunto com plugins externos que serão importados na aplicação. Desta maneira, o desenvolvedor que está realizando a integração destes plugins tem acesso a informações primordiais, como os tipos de valores esperados por um objeto, se um parâmetro é obrigatório, o tipo de um atributo e a interface de uma classe. O seu uso é bastante extenso.

Segue um exemplo da declaração de um arquivo d.ts e sua utilização.

// types/common/functions.d.ts
type GetFullName = ( p: Product ) => string;

// module/product/controller.ts
const getProductFullName: GetFullName = ( p: Product ) => {
    return `${p.ref} ${p.name}`
}

Um ponto a ser destacado aqui, é que a declaração de arquivos d.ts para uso na própria aplicação de um código desenvolvido na própria aplicação, é quase que irrelevante, tendo em vista que naturalmente trabalhamos com interfaces, tipos, e classes internamente.

A declaração desses tipos se faz necessária quando importamos um plugin, ou desejamos fornecer os tipos quando o plugin está sendo desenvolvido por nós, para facilitar outros desenvolvedores. A geração desses arquivos, acabam também por serem automáticas caso já se esteja utilizando o TypeScript. Alguns plugins, que não fornecem esse sistema de tipagem nativamente, permitem também a disponibilização por meio da instalação de tipos externos, como veremos mais a frente.

Esse é um assunto muito amplo, caso queira se aprofundar, recomendo a leitura do site oficial: https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html.

Configurando um projeto em TypeScript

Agora vamos configurar e criar um projeto funcional em TypeScript. O projeto será uma api que fornecerá uma lista fixa de produtos, e que permitirá a recuperação de um produto específico. Utilizaremos também o Express para servir a aplicação, e ele nos permitirá também ver na prática a instalação das declarações de tipos do TypeScript.

O projeto tem o intuito de fornecer uma base, e também uma implementação simples que nos permita focar na essência do uso do TypeScript.

Partiremos do pressuposto que o Node e o NPM já estão disponibilizados em seu ambiente de desenvolvimento. Crie uma pasta num local de sua preferência, e rode o seguinte comando para inicializar o projeto.

npm init -y

Agora, instalaremos o pacote do TypeScript como uma dependência de desenvolvimento.

npm install -D typescript

Por que a instalação do TypeScript?

O Node.js executará o código JavaScript, e não o TypeScript. O pacote do TypeScript permitirá a você transformar os seus arquivos .ts em arquivos .js . Outras ferramentas, como o Babel, podem realizar esta mesma funcionalidade, mas seguiremos o padrão oficial.

No nosso arquivo package.json, colocaremos na tag scripts o seguinte comando:

"scripts": {
    "tsc": "tsc"
},

Esta modificação nos permitirá executar o TypeScript através da linha de comando na pasta do projeto. Outra opção, seria realizar a instalação do TypeScript globalmente, mas para manter as nossas dependências bem organizadas, manteremos assim. Agora podemos executar o seguinte comando:

npm run build -- --init

Este comando irá inicializar o typescript em nosso projeto criando um arquivo tsconfig.json. Não se assuste com a quantidade de opções, no geral, poucas coisas precisarão ser alteradas. No nosso caso, precisaremos apenas tirar o comentário da linha da opção “outDir” e colocar um valor “./build”, para que o nosso código transpilado seja inserido nesta pasta. Como na imagem a seguir.

Configuração typescript outdir
Configuração typescript outdir
Instalação do Express.js e declaração de tipos (d.ts)

Agora realizaremos a instalação do Express para que possamos servir a nossa aplicação.

npm install express

Como explicado anteriormente, alguns plugins por padrão disponibilizam as declarações de seus tipos em pacotes diferentes, como é o caso do Express.js. Neste caso, precisaremos realizar a instalação de um pacote específico para que a nossa aplicação reconheça os tipos do Express.

npm install -D @types/express
Codificando o projeto

Na raiz de nosso projeto, criaremos uma pasta de nome app, e nela criaremos um arquivo de nome app.ts com o seguinte conteúdo:

import express, {Application, Request, Response} from 'express'

const app: Application = express()

const products = [
  {id: '1', name: 'Produto 1'},
  {id: '2', name: 'Produto 2'},
  {id: '3', name: 'Produto 3'},
]

app.get('/', (req: Request, res:Response) => {
  res.send('Hello Word')
})

app.get('/products', (req: Request, res:Response) => {
  res.json(products)
})

app.get('/products/:id', (req: Request, res:Response) => {
  const id = req.params.id
  const product = products.find(item => item.id === id)

  if(!product) {
    return res.status(404).send('Not found')
  }

  res.json(product)
})

app.listen(3000, () => {
  console.log('Server online on port 3000')
})

Resumidamente, importamos o express e suas interfaces disponibilizadas pelo pacote de declaração de tipos. Utilizamos então essas interfaces em nosso código para termos acesso descritivo aos recursos disponibilizados. Em alguns casos, a declaração pode ser opcional tendo em vista que implicitamente a IDE pode vir a reconhecer esses recursos automaticamente.

Segue um exemplo de autocomplete com base na interface.

TypeScript Autocomplete Express
TypeScript Autocomplete Express
Compilando e executando o projeto

Para compilar a aplicação, e gerar os nossos arquivos para produção, apenas precisamos executar o comando a seguir:

npm run tsc

Como você pode ver, o comando anterior irá gerar a pasta .build como a seguir:

Executando a aplicação

Na pasta do projeto, rode o seguinte comando para levantar o server Express

node build/app.js

Acessando o localhost na porta especificada, e acessando as urls definidas, teremos os seguintes resultados:

Ambiente de desenvolvimento mais produtivo

É possível executar a aplicação em TypeScript sem realizar a compilação propriamente dita, utilizando o ts-node . Isso evita ter que ficar compilando a aplicação a todo o momento para poder executá-la. Esta funcionalidade é recomendada apenas para o ambiente de desenvolvimento. O projeto final a ir para produção, sempre utilize a versão do build em JavaScript.

Porém, mesmo utilizando o pacote ts-node, demanda um trabalho extra ter que ficar executando o comando sempre que realizamos uma modificação nos arquivos da aplicação. E é por isso, que instalaremos agora, o pacote ts-node-dev , esse pacote reiniciará a aplicação sempre que realizarmos alguma modificação e salvar o arquivo. 

npm install -D ts-node-dev

E acrescentaremos em nosso package.json, os seguintes valores na tag scripts

"scripts": {
    "tsc": "tsc",
    "dev": "ts-node-dev --respawn --transpile-only --ignore-watch node_modules ./app/app.ts",
    "prod": "tsc && node build/app.js"
}

Para iniciar o projeto em ambiente de desenvolvimento, execute:

npm run dev

Com a aplicação estando inicializada em ambiente de desenvolvimento, realize qualquer modificação nos arquivos da aplicação para ver o servidor sendo reiniciado automaticamente.

Para iniciar o projeto em ambiente de produção, execute:

npm run prod

Código do Projeto: Caso queira acessar os arquivos do projeto, acesse o link do projeto no Github: https://github.com/udewiselabs/article-code-como-e-porque-usar-typescript

***

Ao longo dos anos, práticas e ferramentas têm ajudado a suprir demandas importantes para o ecossistema do JavaScript, como as citadas neste artigo. O TypeScript, pode se dizer que, passa uma segurança a mais, tornando assim a implementação da linguagem mais segura e mais aceitável em grandes projetos. Hoje, podemos ver o mercado global aderindo cada vez mais ao JavaScript, e consequentemente, também ao TypeScript.

1 like |
Gostou? Adicione aos seus artigos
Próxima leitura
Não sabe por onde começar?

Receba conteúdos em primeira mão e fique por dentro das novidades! Junte-se a nós.

É rápido e prático. Cadastre-se ou inscreva-se em nossa newsletters, e pronto.