1

I'm trying to write type definitions for an "async-route" wrapper for express.js. I'm new to typescript, just learned about generics.

As the function could be called behind middlewares that extend the default express Request I want to create it so users can provide their own extended "Request".

So far I have gotten to:

asyncRoute.ts

import { NextFunction } from 'express';

type Fn = <R, S>(req: R, res: S, next?: NextFunction) => Promise<any>;

export default function asyncRoute<R, S> (fn: Fn) {
  return function asyncRouteWrap(req: R, res: S, next: NextFunction) {
    Promise.resolve(fn<R,S>(req, res, next)).catch(next);
  };
};

Usage:

import { Request } from 'express';

interface AppRequest extends Request {
  log: Logger;
  // ...other stuff
}

router.get(
  '/',
  asyncRoute<AppRequest, AppResponse>(async (req, res) => {
    req.log.info('test');
  })
);

But I get Property 'log' does not exist on type 'Request'.

1 Answer 1

2

The problem is that the TypeScript compiler cannot infer the type of req in the anonymous function parameter of asyncRouter. If you have IDE support for TypeScript you will see that fn<R, S>(req, res, next) does not have R bound to AppRequest (in VS Code you only need to hover over the specific line of code).

You can solve your problem by explicitely adding type parameters to Fn in your definition of asyncRoute. For this, you need to first add type parameters to your type definition for Fn

type Fn<R, S> = (req: R, res: S, next?: NextFunction) => Promise<any>

and then define asyncRoute as follows

export default function asyncRoute<R, S> (fn: Fn<R, S>) { 
  return function asyncRouteWrap(req: R, res: S, next: NextFunction) {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
};

The type error should be gone now.


Here's a Typescript Playground with the full code. This contains a few mocked interfaces/types but I'm sure you'll get the point.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.