Exporting the extended express request in a TypeScript library for seamless integration

I have been working on developing a library that extends the express Response object with a custom method called warn(). I want this new warn() method to be easily accessible when using the library.

Here is the configuration in my tsconfig.json:

{
  "compilerOptions": {
    "module": "commonjs",
    "esModuleInterop": true,
    "declaration": true,
    "target": "es6",
    "moduleResolution": "node",
    "sourceMap": true,
    "outDir": "dist",
    "baseUrl": ".",
    "paths": {
      "*": ["node_modules/*"]
    },
    "types": ["mocha"],
    "typeRoots": ["@types"]
  },
  "include": ["src/**/*", "test/**/*"]
}

In the @types/express/index.d.ts file:

import * as express from 'express'
import http from 'http'

export {}

declare global {
  namespace Express {
    export interface Response<ResBody = any>
      extends http.ServerResponse,
        express.Response {
      warn(): this
    }
  }
}

The content of src/registerwarn.ts is as follows:

export function registerwarn() {
  return (_req: Request, res: Express.Response, next): void => {
    res.warn = (): Express.Response => {
      console.log("warning");
      return res;
    };
    return next();
  };
}

src/warnings.ts imports and exports functions:

import { registerwarn } from './registerwarn'
export default [registerwarn()]

A sample test script located in test/warningtest.ts:

import 'should'
import express, { Request, Response } from 'express'
import warnings from '../src/warnings'

describe('test', (): void => {
  const app = express()
  app.use(warnings)
  app.get('/', (req: Request, res: Response) => {
    res.status(200).warn().send({ some: 'content' })
  })
  it('should ', (done) => {
    done()
  })
})

Upon running tsc, I encountered the following errors:

src/registerwarn.ts:3:9 - error TS2339: Property 'warn' does not exist on type 'Response'.

     res.warn = (): Express.Response => {
         ~~~~

test/hello_tests.ts:9:21 - error TS2339: Property 'warn' does not exist on type 'Response<any>'.

     res.status(200).warn().send({ some: 'content' })
                     ~~~~


Found 2 errors.

error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

I am seeking advice on how to resolve these errors and ensure that users of the library from npm do not encounter similar issues. More details can be found in the repro provided here.

Answer №1

I have identified two potential solutions for this issue, however, I cannot confirm if these are the optimal solutions available - they are simply what I have come up with.

Preferred Solution: Eliminate mocha from the globally declared types in your tsconfig.json

According to the information provided on tsconfig.json's compilerOptions.types documentation, including mocha under types will restrict the visibility of @types packages significantly.

By default, all visible "@types" packages are included in your compilation. Packages within node_modules/@types in any enclosing folder are considered visible. If types is specified, only the listed packages will be included in the global scope.

If you remove compilerOptions.types flag completely, your typings should become visible.

In your test file, you should import 'mocha' to access testing methods (e.g. describe, it, etc). This import declaration should be included in each test. Using an explicit import helps clarify where your declarations originate from, rather than them appearing invisibly as a result of your tsconfig.json.

It may not be ideal to declare mocha globally here either because mocha test imports would automatically be visible under files in the src folder, potentially leading to other unexpected errors.

Alternative Solution: Include your @types .d.ts declarations explicitly under the include field.

Through specifying the compilerOptions.types flag, visibility of your custom @types directory is eliminated. You can work around this by modifying the include flag from

To address typing errors in the project post-solving the above issues:

  • The typings for your warnings sources do not seem compatible with any app.use overload. The error
    no matching type overload for <code>app.use(warnings)
  • You do not require to specify any extends for your Response interface - interfaces under the same namespace will merge. Removing the extends clause resolves the error and maintains the desired functionality.

After resolving these typing matters, tsc should exit without any errors being reported.


On a side note unrelated to the main question, your prettier configuration seems to be struggling with CRLF/\r\n line endings. It might be beneficial to adjust your configuration settings or include a .gitattributes file in your Git repository to ensure consistent line endings.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the correct way to assign a property to a function's scope?

Lately, I've been delving into Typescript Decorators to address a specific issue in my application. Using a JS bridge to communicate TS code between Android and iOS, we currently define functions as follows: index.js import foo from './bar' ...

Error encountered during conversion to Typescript for select event and default value

When trying to set the defaultValue in a Select component, TSlint throws an error - Type 'string' is not assignable to type 'ChangeEvent<HTMLInputElement> | undefined - for the code snippet below: const App = () => { const [ mont ...

Setting a Fixed Default Value in an Angular Dropdown Menu

Within my code, there is a specific column where users have the ability to insert an element and choose its priority type while doing so. I am currently attempting to assign a default value to the dropdown selection (row.PriorityType.Id ==1). Although I at ...

Next.js allows for the wrapping of a server component within a client component, seamlessly

I am currently working on a project where I have implemented a form to add data to a JSON using GraphQL and Apollo Client. The project is built with TypeScript and Next.js/React. However, I am facing a conflicting error regarding server client components ...

Having trouble with a tslint error in Typescript when creating a reducer

I encountered an error while working with a simple reducer in ngRx, specifically with the on() method. https://i.sstatic.net/9fsvj.png In addition, I came across some errors in the reducer_creator.d.ts file: https://i.sstatic.net/sWvMu.png https://i.ss ...

An issue has been encountered in Angular while running the ng serve command, indicating that a certain module has not

import { MsalInterceptor } from '@azure/msal-angular/msal.interceptor'; Although the module has been declared without errors in VS Code, I am encountering an error in the command prompt stating that the module is not found. However, upon manual ...

To close the Muix DateTimePicker, simply hit the Escape key or click anywhere outside of the picker

I'd like the DateTimePicker to only close when the user presses the action buttons, not when they click outside or press Escape. Unfortunately, I haven't found any props to control this behavior yet. <DesktopDatePicker closeOnSelect={false} s ...

Angular Delight: Jaw-Dropping Animation

After setting up my first Angular project, I wanted to incorporate Angular Animations to bring life to my content as the user scrolls through the page. I aimed to not only have the content appear on scroll but also implement a staggering animation effect. ...

Tips for accessing a RouterState from the @ngxs/router-plugin before and during the initialization of other states

Previously, in an Angular 8.0.0 and 3.5.0 NGXS application, I successfully retrieved the RouterState using SelectSnapshot from the @ngxs/router-plugin within other states before component rendering. However, in my latest application, the RouterState now re ...

Retrieve Information in a List

I am currently facing an issue while trying to retrieve data from an array. Below is an example of the image array that I am working with. I am specifically looking to get the weather icon data, but unfortunately I encountered this error message: core.js:1 ...

Troubleshooting Typescript and Redux: Implicitly assigning an 'any' type to the binding element 'string'

Within my React Native app designed for Android, I've integrated a component that relies on the Redux library. Referencing "Hemant" from this thread, it was advised to pass the action as an imported prop into the component. However, I'm encounte ...

The setInterval method in Typescript/Javascript is unable to invoke other functions

I have a situation where I need to call the function callMe() every 1000 ms. While this setup is functioning as expected, I am encountering an issue when trying to call another function from within callMe(). The error message I am receiving is: uncaught ...

The module 'angular' could not be located and is causing an error

Currently, I am in the process of transitioning from Angular 1 to Angular 2 following this guide: . However, when I try to run the application using npm start, it displays an error saying 'Cannot find module 'angular''. This is a snipp ...

Unable to grab hold of specific child element within parent DOM element

Important Note: Due to the complexity of the issue, the code has been abstracted for better readability Consider a parent component structure like this: <child-component></child-component> <button (click)="doSomeClick()"> Do Some Click ...

What is the method for expanding an object type using a string literal type?

I am encountering an issue with the code snippet below. In this code, type B is meant to extend type A by expanding the acceptable values for the property type. However, despite this intention, the assignment is resulting in a type error. type A = { ...

How come the variable `T` has been assigned two distinct types?

Consider the following code snippet: function test<T extends unknown[]>(source: [...T], b: T) { return b; } const arg = [1, 'hello', { a: 1 }] const res = test(arg, []) const res1 = test([1, 'hello', { a: 1 }], []) The variabl ...

The name 'Map' cannot be located. Is it necessary to alter your target library?

After running the command tsc app.ts, an error occurs showing: Error TS2583: 'Map' is not recognized. Should the target library be changed? Consider updating the lib compiler option to es2015 or newer. I want the code to compile without any issu ...

Exploring the power of Typescript and Map in Node.js applications

I am feeling a little perplexed about implementing Map in my nodejs project. In order to utilize Map, I need to change the compile target to ES6. However, doing so results in outputted js files that contain ES6 imports which causes issues with node. Is t ...

Error in Nestjs Swagger: UnhandledPromiseRejectionWarning - The property `prototype` cannot be destructed from an 'undefined' or 'null' object

Currently, I am in the process of developing a Nestjs REST API project and need to integrate swagger. For reference, I followed this repository: https://github.com/nestjs/nest/tree/master/sample/11-swagger However, during the setup, I encountered the foll ...

What is the reason for TypeScript resolving this type union as an intersection?

I'm struggling to grasp the logic behind a typescript error that keeps popping up - it feels like there's a fundamental concept swiftly flying over my head, making a "whoosh" sound as it goes by. I stumbled upon this discussion about a similar e ...