ExpressJs Request Params Override Error

I am currently utilizing express version 4.19.2 (the latest available at the time of writing)

This is how I have declared the generic type Request

interface ParamsDictionary {
  [key: string]: string;
}

interface Request<
  P = core.ParamsDictionary,
  ResBody = any,
  ReqBody = any,
  ReqQuery = core.Query,
  Locals extends Record<string, any> = Record<string, any>,
> extends core.Request<P, ResBody, ReqBody, ReqQuery, Locals> {}

I am attempting to override 'P' or 'Params', in order to reference the actual type within my route handler. However, I encountered this error:

Type '(req: Request<ItemParam, unknown, ItemBody, unknown, JwtUser>, res: Response, next: NextFunction) => Promise<void>' is not assignable to type 'RequestHandler<ParamsDictionary, unknown, ItemBody, ParsedQs, JwtUser>'

Types of property 'params' are incompatible. Property 'itemId' is missing in type 'ParamsDictionary' but required in type 'ItemParam'

Here are snippets from my code:

interface ItemParam {
  itemId: string;
}

const myHandler = async (
    // ✅ No TypeScript error here
    req: Request<ItemParam, unknown, ItemBody, unknown, JwtUser>,
    res: Response,
    next: NextFunction,
  ): Promise<void> => {
   const { itemId } = req.params; // ✅ Can refer to itemId
   const { amount } = req.body; // ✅ Can refer to amount
};

// ❌ However, I encounter an error in the route
router.route('/:itemId').put(
  validate({
    params: {
      itemId: Joi.string().required(),
    },
  }),
  myHandler, // ❌ Error occurs as shown above
);

No TypeScript error occurs if I remove 'validate':

// ✅ This works
router.route('/:itemId').put(
      myHandler,
    );

I also do not receive an error if I override my handler like this:

// ✅ This works
Request<{ itemId: string }, unknown, PlaceBidItemBody, unknown, JwtUser>

While I can use the above workaround, could someone please help me understand the issue or confirm if this is a bug in express?

UPDATE / POSSIBLE SOLUTION I modified the ItemParam type to:

interface ItemParam {
  itemId: string;
  [key: string]: string;
}

I prefer not to extend from ParamsDictionary since it is part of the pre-included package express-server-static-code, and generally not recommended to reference anything from packages you did not explicitly install.

If anyone could help me grasp why the original ItemParam is not directly compatible with ParamsDictionary, I would greatly appreciate it!

Answer №1

After conducting some thorough research to comprehend and assess the regulations, I have compiled a few essential reminders:

  1. itemId is categorized as a literal type, distinct from string or number types. Despite its name suggesting it is a string, it is not merely classified as such. This means arbitrary string values cannot be assigned to this type directly. For instance.
type Status = 'success' | 'failed'
const status1: Status = 'error'; ❌
const status2: Status = 'success'; ✅

Although this concept may seem rudimentary, my realization of it was somewhat incomplete until now. Particularly, I got carried away in understanding how Body can accept an interface while Param (as well as Query) cannot. My aim is to maintain organized and reusable code through interfaces and types.

  1. Diving deeper into the matter, the discrepancy and limitations in types between Param, Query, and Body roots from the workings of browsers – property values are restricted to strings unlike Body, which can accommodate numbers, booleans, and even null aside from strings.

Param: The value of parameter id will always be interpreted as a string "1000678"

http://example.com/api/sample/:id
http://example.com/api/sample/1000678

Query: The value of query variable id will consistently be treated as a string

http://example.com/api/sample?id=1000678

Body via Post/Put requests: The value of id can be a numeric data type and will be processed accordingly

{
   "id": 1000678,
}

SOLUTION

To ensure the key remains a string type while upholding the strong typing feature of the interface, consider the following approach:

interface ItemParam extends Record<string, string> {
  itemId: string;
}

interface ItemParam {
  itemId: string;
  [key: string]: string;
}

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

Setting up webpack with a live server for your project is a crucial step

I am a beginner with webpack. I successfully configured this module for localhost, but now I need to host it. However, when I changed the IP address in the webpack.config.js file, it stopped working. Below is the content of my webpack.config.js:</p> ...

Combine Typescript files from a dependent module to aid in debugging within a Next.js application

Trying to debug a project written in Typescript using Next.js, but facing issues with bundling TS files from a local dependent common library. Only JS files are included, which is not sufficient for debugging. The goal is to bundle all TS files from the w ...

Issue with file uploading in Angular 9 as the uploaded file is not being added to the

I've set up a form group in the HTML of my Angular 9 app that includes an upload feature for files. The file upload works fine when calling the handleFileInput function, as I can confirm from the console log output. However, even though the file gets ...

I am encountering an issue trying to establish a connection with my socket server. Unfortunately, the server is not successfully connecting

Currently, I am in the process of building a socket server with node js and express. However, when I attempt to run it, I encounter an error message in Postman which can be viewed here. Below is the code snippet that I am working with: App is an express s ...

Utilize the gsap ScrollTrigger in conjunction with React's useRef() and Typescript, encountering issues with type mism

Recently, I've been trying to add some animation to a simple React Component using the GreenSock ScrollTrigger plugin. However, I ran into an issue due to types mismatch in my Typescript project. Here's a snippet of the code: import React, {useRe ...

Angular $resource failing to transfer parameter to Express endpoint

I am currently working on an Angular application that needs to retrieve data from a MongoDB collection. To accomplish this, I am utilizing the $resource service within the flConstruct. The "query" function works well as it returns all data from the server ...

Prevent users from clicking buttons until all mandatory fields are filled out using react-hook-form

I am seeking guidance on how to dynamically disable a button based on the input values of both Name and State in the given code snippet. Specifically, I want to restrict button functionality until both name and state fields are filled out, regardless of ...

Save the ID values of selected users in Angular Mentions feature

Using the angular mentions library, I successfully incorporated a textarea that enables me to mention multiple users. Is there a method to store the IDs of the selected users? Ideally, I would like to save them as an array of strings. For instance: If I ...

Angular2: Unable to locate the 'environment' namespace

After configuring my tsconfig.json, I can now use short import paths in my code for brevity. This allows me to do things like import { FooService } from 'core' instead of the longer import { FooService } from '../../../core/services/foo/foo. ...

Opensuse is having trouble running a recently created React/Node.js project

Currently, I am in the process of learning Express and react. Initially, I was able to successfully run a react app. However, when starting a new web app yesterday, I encountered issues preventing a freshly created react app from crashing. My System: o ...

The act of saving in Mongoose does not truly result in data being persisted

Currently, I am facing a strange issue where I update my record, see the updated data within the callback function of save(), but upon checking the database, the changes are not actually saved: Skills.findOne({ skillsCat: req.body.skillsCat }, (err, gets) ...

Node.js - Headers cannot be sent again once they have been sent

I came across a similar issue to mine at this link. I suspect that the error is occurring due to how my .end() calls are configured. Let's take a look at the code in question: app.get('/anihome',function(req,res){ var context = {}; functi ...

Discover the seamless transformation of a class definition into a Vue 3 component definition utilizing the dazzling 'tc39' decorators

The proposed API in the tc39/proposal-decorators repository is significantly different from the previous decorators API. Although TypeScript 5 doesn't fully support the new API yet, it's only a matter of time before the old API becomes deprecated ...

The Postman application is unable to fulfill the request because it encountered an issue with utilizing its environment variable for

Currently, I am developing a REST API using Node.js and Express for a project. In this project, the user is required to sign up or log in to receive a JWT token for authentication. This JWT token allows the user to access protected routes within the applic ...

Top recommendations for implementing private/authentication routes in NextJS 13

When working with routes affected by a user's authentication status in NextJS 13, what is the most effective approach? I have two specific scenarios that I'm unsure about implementing: What is the best method for redirecting an unauthenticated ...

Tips on altering the Vue state upon clicking the checkbox

I am currently in the process of developing a To-Do Application utilizing Vue.js, Express.js, and MongoDB. My goal is to modify the status of the items displayed using v-for through the checkbox functionality. The desired outcome is to alter the state of ...

Experiencing difficulties when trying to set up the express/body-parser node js eclipse

I'm currently working my way through the instructions for setting up express web servers using the eclipse/node js plugin in a tutorial book, and I am struggling to install express or create the necessary subfolders as instructed. Despite following th ...

Transforming XML into Json using HTML string information in angular 8

I am currently facing a challenge with converting an XML document to JSON. The issue arises when some of the string fields within the XML contain HTML tags. Here is how the original XML looks: <title> <html> <p>test</p> ...

Using a combination of nested fetch() and array.map() does not allow for the return

My previous coding experience didn't present any issues with rendering HTML. Typically, I only needed to use one fetch() function. However, in this particular scenario, it appears that I require two fetch calls. The first fetch retrieves a product ID ...

How come TypeScript tuples support the array.push method?

In the TypeScript code snippet below, I have specified the role to be of Tuple type, meaning only 2 values of a specified type should be allowed in the role array. Despite this, I am still able to push a new item into the array. Why is the TS compiler not ...