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 ?
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.
Next.JS types can be overwritten for example when using a custom server.
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:
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.
Most helpful comment
Hi @Neophy7e, thank you for filling this issue 馃挴 , the current
reqandreswere made thinking only in thehttpmodule, and that's firing back actually, the only way you can actually extend it is by extendingIncomingMessage, but it's aclassand not aninterfaceso it's not possible 馃槩. For the moment the best solution I can think of is switch to useas RequestHere's an alternative solution that can be implemented in Next.js, what if instead of
we use
And
NextRequestwould just beit should allow declaration merging so you can add custom properties on it like this
or even