Skip to content

Instantly share code, notes, and snippets.

@IagoPFerreira
Last active April 25, 2024 11:20
Show Gist options
  • Save IagoPFerreira/2352dd4018f697a5a569425ca73755fe to your computer and use it in GitHub Desktop.
Save IagoPFerreira/2352dd4018f697a5a569425ca73755fe to your computer and use it in GitHub Desktop.

Criando o Express com TypeScipt

Criando um projeto

  1. Criar um diretório
mkdir <nome-do-diretório> && cd <nome-do-diretório>
  1. Iniciar a aplicação
npm init -y

Pacotes do TypeScript

  1. Instalar o TypeScipt
npm install -D typescript
  1. Instalar o @types/node
npm install -D @types/node
  1. Instalar o ts-node-dev
npm install -D ts-node-dev
  • Atalho
npm install -D typescript @types/node ts-node-dev

Configurando o .tsconfig

  1. Criar o .tsconfig
npx tsc --init
  1. Garantir as seguintes configurações
{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "rootDir": "./src",
    "outDir": "./dist",
    "esModuleInterop": true,
    "strict": true
  }
}

Pacotes do express

  1. Instalar o express
npm install express
  1. Instalar o @types/express
npm install -D @types/express
  1. Instale a biblioteca express-async-errors

Essa biblioteca ajuda com tratamento de erros sem precisar usar try/catch

npm install express-async-errors

Importe a biblioteca logo após a importação do express;

  1. Instalar a biblioteca http-status-codes ❗️ Opcional ❗️
npm install http-status-codes

Iniciando uma aplicação Express

  1. Crie os arquivos index.ts e app.ts dentro do diretório src
touch src/index.ts src/app.ts
  1. Você pode usar os templates abaixo nos seus arquivos ❗️ Opcional ❗️
// src/index.ts

import app from './app';

const PORT = 8000;

app.listen(PORT, () => {
  console.log(`Server is running at http://localhost:${PORT}`);
});
// src/app.ts

import express from 'express';
import 'express-async-errors';
import { StatusCodes } from 'http-status-codes';

const app = express();

app.use(express.json());

app.get('/', (req, res) => {
  res.status(StatusCodes.OK).send('Express + TypeScript')
});

export default app;
  1. Crie scripts no arquivo package.json
...
"scripts": {
    "start": "npm run build && node ./dist/index.js",
    "dev": "tsnd index.ts",
    "build": "tsc"
 },
...
  • start: executa o build da aplicação e depois roda o arquivo compilado dentro da pasta dist;
  • dev: executa a aplicação em modo de desenvolvimento utilizando o ts-node-dev;
  • build: executa a compilação do projeto utilizando o TSC.
  1. Execute a aplicação
npm start

Refatorando o app.ts

  1. Incluindo tipos no app.ts
// src/app.ts

import express, { Request, Response } from 'express';
import 'express-async-errors';
import { StatusCodes } from 'http-status-codes';

const app = express();

app.use(express.json());

app.get('/', (req: Request, res: Response) => {
  res.status(StatusCodes.OK).send('Express + TypeScript')
});

export default app;
  1. Incluindo um middleware de erro
// src/app.ts

import express, { Request, Response, ErrorRequestHandler } from 'express';
// import 'express-async-errors';
// import { StatusCodes } from 'http-status-codes';
//
// const app = express();
//
// app.use(express.json());
//
// app.get('/', (req: Request, res: Response) => {
//   res.status(StatusCodes.OK).send('Express + TypeScript')
// });

const erroMiddleware: ErrorRequestHandler = (err, req, res, next) => {
  const { name, message, details } = err;
  console.log(`name: ${name}`);

  switch (name) {
    case 'ValidationError':
      res.status(400).json({ message: details[0].message });
      break;
    case 'NotFoundError':
      res.status(404).json({ message });
      break;
    case 'ConflictError':
      res.status(409).json({ message });
      break;
    default:
      console.error(err);
      res.sendStatus(500);
  }

  next();
};

app.use(erroMiddleware);

// export default app;

Pacotes do adicionais

  1. Instale as bibliotecas restify-errors e @types/restify-errors ❗️ Opcional ❗️

Essas bibliotecas ajudam com disparos de erros específicos

npm install restify-errors @types/restify-errors
@isaacbatst
Copy link

isaacbatst commented Aug 11, 2022

Melhoraria o error handling, não tipando pra any e já desestruturando, mas fazendo um narrowing garantindo o type safety do código:

app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  if(error instanceOf Error) {
    const { name, message, details } = error // acredito que `Error` não tem `details`, então vale ir mais afundo criando uma classe CustomError que tem o details 
    switch (name) {
      case 'ValidationError':
        return res.status(400).json({ message: details[0].message });
      case 'NotFoundError':
        return res.status(404).json({ message });
      case 'ConflictError':
        return res.status(409).json({ message });
      default:
        console.error(err);
        return res.sendStatus(500);
    }

     console.log(`name: ${name}`);
  }

  return res.sendStatus(500);
});

@renatosousafilho
Copy link

Sobre o tópico 12, sugiro fazer a separação entre os arquivos app.ts e index.ts visando a questão dos testes de integração.

@renatosousafilho
Copy link

Outra sugestão é manter o uso do express-async-erros por padrão e contemplar seu setup já no tópico 15.

@IagoPFerreira
Copy link
Author

@isaacbatst fiz a alteração que o Ivan sugeriu durante a mentoria, de colocar o middleware em uma função a parte

@renatosousafilho fiz as duas correções

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment