Node.js e TypeScript: O como e com testes
Todas as vantagens do TypeScript no seu servidor!

Você já leu por aqui como converter React.js para TypeScript. Falamos também sobre como configurar React Native e TypeScript! Você se lembra que até cobrimos como utilizar TypeScript sem utilizar TypeScript? Vou te dizer, é tanto <T>(a: T): U & F que dói a cabeça! 🤕🤒… Pensando nisso, nós tivemos um artigo completo de como entender a notação de tipos em TypeScript.
Falamos da sintaxe do TypeScript, front-end com React, aplicações nativas com React Native e, dentro do ecossistema JavaScript, só ficou de fora o nosso back-end. 😭
Atualização - 19 Outubro 2018: Após o comentário do leitor Bruno Dutra Franco, atualizei o repositório adicionando exemplos de “Debugging”. Você pode usar debug in-editor com o VSCode ou a CLI do Node.js e abrir um aba do Google Chrome. Informações completas no README do repositório!
Atualização - 04 Setembro 2018: Coloquei o exemplo descrito nesse artigo em um repositório, ficando mais fácil para ver o código completo:
Node.js ao resgate
Iremos instalar os pacotes básicos para ter uma aplicação Node.js rodando com TypeScript e todas suas vantagens:
$ mkdir node-typescript
$ cd node-typescript
$ npm init -yVamos instalar as primeiras depêndencias:
$ npm i typescript nodemon ts-nodeE rodar o comando init no recém instalado módulo do typescript:
$ ./node_modules/.bin/tsc --initIsso irá gerar um arquivo tsconfig.json na sua pasta. Essas são as configurações que serão passadas para o compilador do TypeScript. Ao abrir esse arquivo, ele irá conter comentários e várias opções, parecido com:

Vamos editar esse arquivo, ficando dessa maneira:
// node-typescript/tsconfig.json{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"outDir": "./dist", "strict": true, "noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true, "esModuleInterop": true
}
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.test.ts"]
}
Tem alguma dúvida sobre as chaves e seus valores? Recomendo primeiro tentar pesquisar/Google. Persistindo a dúvida comente aqui embaixo :)
Agora, iremos editar nosso package.json :
// node-typescript/package.json{
"name": "node-typescript",
"version": "1.0.0",
"private": true,
"scripts": {
// [A]
"dev": "nodemon --watch "src/" --exec \"ts-node src/entry.ts\" -e ts"
},
"dependencies": {
"nodemon": "^1.18.4",
"ts-node": "^7.0.1",
"typescript": "^3.0.3"
}
}
- [A]: nodemon irá observar,
--watch, o diretório src e executar,--exec, o script,"ts-node src/entry.ts", a qualquer mudança de arquivo com extensão ts,-e ts
Antes de seguir em frente, vamos instalar o framework mais querido do Node.js, express:
$ npm i express @types/expressSeguindo o comando "dev" acima, vamos criar src/entry.ts:
// node-typescript/src/entry.tsimport server from './server';server.listen(3000, () => {
console.log(`[SERVER] Running at http://localhost:3000`);
});
Opa! Esse arquivo está buscando server em "./server". Então, vamos criar nosso src/server.ts:
// node-typescript/src/server.tsimport express from "express";const server = express();server.get("/", (_, res) => {
res.send("Hello ts-node!");
});export default server;
Agora, podemos utilizar npm run dev e:


Hooray! 🎉🎉
Se você usa VSCode, a integração com o editor é fantástica, auto-completando seus métodos e acessos de objetos. Ah! Você percebeu que estamos utilizando a sintaxe ES6? ;)
No cap, bro! 😎
Adicionando testes com Jest
Jest é a maneira mais divertida de escrever testes. E em Node.js com TypeScript, não é diferente! Vamos instalar as depêndencias:
$ npm i @types/jest jest ts-jestAgora precisamos dizer ao Jest para utilizar o compilador do TypeScript e também procurar por arquivos .ts. Vamos adicionar essa configuração extra do Jest no package.json :
// node-typescript/package.json{
// ...outras regras do seu `package.json`
"jest": {
"transform": {
"^.+\\.ts$": "ts-jest" // [A]
},
"testRegex": "\\.test\\.ts", // [B]
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node" // [C]
]
}
}
- [A]: estamos dizendo ao Jest que, ao encontrar arquivos .ts utilize o ts-jest como parte da transformação/resolução do módulo
- [B]: minha preferência pessoal são arquivos <nome>.test.js, sempre co-locados com o arquivo testado, você pode mudar essa RegEx
- [C]: precisamos declarar todas essas extensões (podemos omitir .tsx/jsx nesse exemplo) pois arquivos de módulos (dentro de node_modules/) precisam ser importados pelo Jest e ou qualquer outra dependência
Para testar nossa aplicação express, iremos utilizar a biblioteca supertest:
$ npm i @types/supertest supertestDentro do nosso package.json , vamos adicionar um script chamado test:
// node-typescript/package.json{
// ...outras regras do seu `package.json`
"scripts": {
// ...outros scripts
"test": "jest --no-cache"
}
}
Agora já temos todas as dependências e o comando correto, vamos criar nosso arquivo src/server.test.ts e escrever nosso primeiro teste:
// node-typescript/src/server.test.tsimport req from "supertest";
import server from "./server";test("[GET] /", async () => {
const res = await req(server).get("/");
expect(res.text).toBe("Hello ts-node!");
});
Ao executar npm run test temos como resultado:

Como você pode ver, ter dividido nossa aplicação express em entry.ts e server.ts, nos ajuda a importar toda a aplicação sem executá-la (essa abordagem é opcional). Também estamos utilizando sintaxe ES6 em nossos testes ;)
Isso funciona em produção?
Olhando de perto nossa configuração, só estamos utilizando ts-node para iniciar nosso servidor. Por padrão, ele executa o compilador do TypeScript, carrega todos os tipos, faz todas análises estáticas etc.
Como comentado no repositório do ts-node, ele não é recomendado para produção. Também não há nenhum benchmark dizendo que há problemas de performance ao usar ts-node, o ponto principal é o consumo de memória, devido ao uso conjunto com o compilador do TypeScript.
Tendo isso em mente, precisamos criar mais uma etapa, o famigerado build!
Porém, se você olhar nossa configuração do TypeScript, lá no começo, o tsconfig.json, nós temos a seguinte chave: "outDir": "./dist". Em outras palavras, já está tudo configurado! 🤓
Vamos adicionar mais 2 comandos ao nosso package.json , um para executar o compilador do TypeScript e imprimir arquivos .js e outro para executar o nosso servidor utilizando esse resultado.
// node-typescript/package.json{
// ...outras regras do seu `package.json`
"scripts": {
// ...outros scripts
"build": "tsc",
"prod": "npm run build && node dist/entry.js"
}
}
E ao executarmos npm run prod , teremos:


Hooray! 🎉🎉
Agora estamos compilando para puro JavaScript e utilizando Node.js para rodar o servidor.
A partir daqui você pode adicionar todas as suas práticas, módulos e pacotes preferidos. Junto da segurança de ter seu código back-end com análise estáticas e todos os benefícios do ecossistema do TypeScript.
Você que chegou até aqui, meu muito obrigado! 🤗
