Next.js: Not able to overwrite next-server type definitions for Express

Created on 16 May 2019  路  10Comments  路  Source: vercel/next.js

Bug report

Describe the bug

I'm using Express as a custom server and my project is setup with Typescript with Next.js v8.1.1-canary.29.

When I want to use req or res express object in getInitialProps of pages/_document.tsx Typescript complain when I access properties that are only defined in express server and not http server (eg: req.ip)

As I usually do with other libraries I tried to override the next-server module type and set req and res to their corresponding express types. https://github.com/Neophy7e/next-js-typescript-overide-example/blob/master/types/next-server.d.ts

But after multiple attempt it seems like I can only add new property to the module but I can't replace existing ones.

Any idea why ?

To Reproduce

I've created a sample repo with bare minimum to showcase the issue :

Typescript complain about this line https://github.com/Neophy7e/next-js-typescript-overide-example/blob/master/pages/_document.tsx#L15

Even when trying to override the DocumentContext type here req type stays IncomingMessage

I haven't set express as a custom server but it assumes it.

Expected behavior

Next.JS types can be overwritten for example when using a custom server.

System information

  • OS: macOS
  • Version of Next.js: v8.1.1-canary.29

Most helpful comment

Hi @Neophy7e, thank you for filling this issue 馃挴 , the current req and res were made thinking only in the http module, and that's firing back actually, the only way you can actually extend it is by extending IncomingMessage, but it's a class and not an interface so it's not possible 馃槩. For the moment the best solution I can think of is switch to use as Request

Here's an alternative solution that can be implemented in Next.js, what if instead of

req?: IncomingMessage

we use

req?: NextRequest

And NextRequest would just be

interface NextRequest extends IncomingMessage

it should allow declaration merging so you can add custom properties on it like this

declare module 'next-server/dist/lib/utils' {
  interface NextRequest {
    ip: string
  }
}

or even

import { Request } from 'express';

declare module 'next-server/dist/lib/utils' {
  interface NextRequest extends Request {}
}

All 10 comments

Hi @Neophy7e, thank you for filling this issue 馃挴 , the current req and res were made thinking only in the http module, and that's firing back actually, the only way you can actually extend it is by extending IncomingMessage, but it's a class and not an interface so it's not possible 馃槩. For the moment the best solution I can think of is switch to use as Request

Here's an alternative solution that can be implemented in Next.js, what if instead of

req?: IncomingMessage

we use

req?: NextRequest

And NextRequest would just be

interface NextRequest extends IncomingMessage

it should allow declaration merging so you can add custom properties on it like this

declare module 'next-server/dist/lib/utils' {
  interface NextRequest {
    ip: string
  }
}

or even

import { Request } from 'express';

declare module 'next-server/dist/lib/utils' {
  interface NextRequest extends Request {}
}

Hey @lfades I think that would totally do it, I could give a try at it in a PR. What do you think ?

@Neophy7e I'm still thinking about whether or not this is a good idea, maybe we should just enforce the usage of http because the serverless target doesn't need this. Do you want to share your use case for having a custom server ?

@lfades I'm using express as custom server with different middlewares.

For example the https://github.com/biggora/express-useragent help me to set the correct data for https://github.com/contra/react-responsive on server side rendering.

It adds new properties to the req object for example the useragent add this req.useragent. I'm also another middleware for locale detection ...

I could probably get around it, but as I understood next.js support custom server and in my project I prefer separating those concerns from the _document file.

I would imagine there must be other use cases where user prefer to use something else than http

@Neophy7e In the case of serverless there's no custom server, so the function is the usual http request handler, in any case I'm going to keep this open as the current stand point may change in the future.

Adding middlewares in this way is actually not the best idea, it's better to keep them per-route. I'm going to close this as we're not planning to change this in the near future.

@timneutkens @lfades am I reading this thread correctly that its now not recommended to use a custom server? Request from express is much different than IncomingMessage from http... is it wrong to utilize req in getInitialProps as an express request object? We are converting to typescript atm and its been illuminating to how we have done things off the books, just trying to get clarity here.

@brad-decker overall with Next.js 9 a custom server is generally not needed anymore. Middlewares, especially server-only middlewares can cause quite a lot of indirection because they obviously don't work on client-side route transitions.
You're able to override the types inline when needed in this case.

I'm curious what you're currently still using express for btw, could you share the custom server, can be in dm's on twitter if you want. https://twitter.com/timneutkens.

@timneutkens

Things our current custom server is doing:

  1. Setting the dir to /src. I believe this can be handled by a flag on the CLI, or maybe now it's even natively supported by I haven't found documentation on how to set it up.
  2. Checking the user's browser and serving a plain HTML unsupported browser page
  3. Putting a password wall up with a randomly generated UUID that is shared internally with our team for PR apps and staging environments.
  4. Enforcing SSL by redirecting to https.
  5. Caching some of our HTML. We use Apollo and gather data on the server and this can be a bottleneck on server performance for us so we cache generated HTML in some / most cases.
  6. Using express helmet
  7. Remove trailing slash from urls
  8. Checking the user's JWT token and disallowing access to authenticated routes
  9. Enabling serving GZIP and Brotli files.
  10. serving a number of static resources such as service-worker, precache-manifest, etc.
  11. Forwarding some requests to our API

I am doing everything I can to remove as much of our customizations from the application as possible. We've eliminated over half of our custom webpack configuration over time with all the great work your team has been doing to make things "Just work"鈩笍. If you'd like to see the code I can share that with you privately but the above list encapsulates all of our need for the custom server.

Hi, just want to chime in and say I also have a custom server with Express middleware using TypeScript and this issue is a problem for us. I can give you a list of features that we use it for if you want, but realistically it seems impossible for Next to cover 100% of every middleware need.

There are official Next.js docs and examples about using a custom server (here, here, and here's one specifically using TS). None of these indicate that using custom middleware in a custom server is unsupported or not recommended. I'd love to see this issue fixed, but short of that, it would be nice if the docs had some info about these limitations up front.

Was this page helpful?
0 / 5 - 0 ratings