question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Not able to overwrite next-server type definitions for Express

See original GitHub issue

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

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:12 (6 by maintainers)

github_iconTop GitHub Comments

4reactions
lfadescommented, May 28, 2019

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 {}
}
3reactions
TroyAlfordcommented, Jan 28, 2021

For anyone else running into this, I was able to extend the types with:

// next-env.d.ts
module 'MyModule' {
  type AppContext = import('next/app').AppContext

  export declare interface MyAppContext extends AppContext {
    ctx: AppContext['ctx'] & {
      req: AppContext['ctx']['req'] & {
        myExtraField: import('./relative/path/to/MyType.ts').MyType,
      },
    },
  }
}
// _app.tsx
import type { MyAppContext } from 'MyModule'

export default class Application extends React.Component<Props, State> {
  static getInitialProps = async (appContext: MyAppContext): Promise<Props> => {
    const appProps = await App.getInitialProps(appContext) as AppProps
    return {
      ...appProps,
      myExtraField: appContext.ctx.req.myExtraField, // this is now correctly typed
    }
  }
  /* the rest of the class */
}

To allow the same kind of typing in my express server, I have:

// express.d.ts
declare namespace Express {
  export interface Request {
    myExtraField: import('./relative/path/to/MyType.ts').MyType,
  }
}

Which allows me to have express middleware, like:

const server = express()
  .use((request, response, next) => {
    request.myExtraField = { some: 'value' } // this is now type-safe
  })

const app = next({ dev })
app.prepare().then(() => server.use('*', app.getRequestHandler()))
  /* other middleware */
  .use('*', myNextApp)
  

The net result is that I can have proper type-safety from my express middleware all the way down into my next custom app’s getInitialProps method.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Not able to overwrite next-server type definitions for Express
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.
Read more >
Set Up Next.js with a Custom Express Server + Typescript
In this post, I will walk you through how to make a Next.js application handled by a custom Express server with Typescript.
Read more >
Overwrite `any` in TypeScript when merging interfaces
I recently ran into this issue and managed to resolve it by creating an index.d.ts in my src folder to overwrite res.locals, ...
Read more >
Basic Features: TypeScript - Next.js
Next.js provides an integrated TypeScript experience, including zero-configuration set up and built-in types for Pages, APIs, and more.
Read more >
Changelog - Cypress Documentation
With this change, cy.session() will no longer fail validation when false is ... new testing-type specific configuration option that must be defined within ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found