0

I'm trying the express route handlers that comes with the documentation to make a chain of function calls in certain order, so I want to pass a value from cb0 to cb1 (or cb2), currently I'm setting a property in the req object and accesing it from another handler, this just work fine.

const express = require('express');
const app = express();
const PORT = 8000;

const cb0 = function (req, res, next) {
  console.log('CB0');
  req.cb0val = 'Hello';
  next();
}

const cb1 = function (req, res, next) {
  console.log('CB1');
  req.cb1val = 'World';
  next();
}

const cb2 = function (req, res) {
  res.send(`Hey, ${req.cb0val} ${req.cb1val}`);
}

app.get('/', [cb0, cb1, cb2])

app.listen(PORT, () => {
  console.log(`⚡️[server]: Server is running at https://localhost:${PORT}`);
});

The problem came when using typescript

import express from 'express';
const app = express();
const PORT = 8000;

const cb0: express.RequestHandler = function (req: express.Request, res: express.Response, next: Function) {
  console.log('CB0');
  req.cb0val = 'Hello';
  next();
}

const cb1: express.RequestHandler = function (req: express.Request, res: express.Response, next: Function) {
  console.log('CB1');
  req.cb1val = 'World';
  next();
}

const cb2: express.RequestHandler = function (req: express.Request, res: express.Response) {
  res.send(`Hey, ${req.cb0val} ${req.cb1val}`);
}

app.get('/example/c', [cb0, cb1, cb2])

app.listen(PORT, () => {
  console.log(`⚡️[server]: Server is running at https://localhost:${PORT}`);
});

Because I'm setting the type of req as express.Request I can't set a new property of that type getting the following errors:

index.ts:7:7 - error TS2339: Property 'cb0val' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs>'.

7   req.cb0val = 'Hello';
        ~~~~~~
index.ts:13:7 - error TS2339: Property 'cb1val' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs>'.

13   req.cb1val = 'World';
         ~~~~~~
index.ts:18:24 - error TS2339: Property 'cb0val' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs>'.

18   res.send(`Hey, ${req.cb0val} ${req.cb1val}`);
                          ~~~~~~
index.ts:18:38 - error TS2339: Property 'cb1val' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs>'.

18   res.send(`Hey, ${req.cb0val} ${req.cb1val}`);
                                        ~~~~~~

What's the correct approach to handle this scenario without changing the type of express.Request to any?

Sergio Flores
  • 5,231
  • 5
  • 37
  • 60

1 Answers1

1

You can use something called Declaration Merging.

Create a file called express.d.ts somewhere in your project. This is typically created in a @types folder in the root of your project (@types/express.d.ts).

The contents of this file should be

declare namespace Express {
    interface Request {
        cb0val: string
        // other custom properties ...
    }
}

In your tsconfig, setup either a typeRoot or add the new file to the types field.

"typeRoots": [
  "@types/",
  "node_modules/@types/"
]
Tyler Sebastian
  • 9,067
  • 6
  • 39
  • 62