Combining type inference validation and authentication middleware in Express routes can be a powerful way to enhance security and ensure

I am struggling to grasp how types are automatically determined in Express routes when utilizing multiple middlewares.

To conduct validation using zod, I have employed the middleware package express-zod-safe, although a similar issue arose with alternative middleware like zod-express-middleware.

One of my middlewares, auth, ideally should execute first to prevent unauthorized access. However, before implementing it, I need to perform validation to ensure accurate type inference:

import express from "express";
import validate from "express-zod-safe";
import { z } from "zod";

const app = express();

export function checkAuth<
  T extends express.Request,
  U extends express.Response,
  V extends express.NextFunction
>() {
  return (req: T, res: U, next: V) => {
    next();
  };
}

const schema = z.object({ id: z.coerce.number().min(0) });

app.get(
  "/api/product/:id",
  validate({ params: schema }), // This line should be after checkAuth
  checkAuth(),
  (req, res) => {
    req.params.test; // The Typescript server only rightfully complains when I validate first
    res.send("Here's a product");
  }
);

app.listen(3000, () => console.log("Server running on port 3000"));

Edit: As I plan to incorporate additional routes with varying params, I aim for the TypeScript server to automatically infer these types while keeping the checkAuth function completely generic.

Edit 2: Initially, I managed to prioritize checkAuth by assigning any to the request type, but this resulted in losing the Request typing within it. How can I merge both types seamlessly?

export function checkAuth() {
  return (req: any, res: any, next: any) => {
    const authorizationHeader = req.headers.authorization;
    next();
  };
}

Edit 3: Following some adjustments using never, I achieved correct typing for both functions:

export function checkAuth() {
  return (req: express.Request<never>, res: any, next: any) => {
    const authorizationHeader = req.headers.authorization;
    next();
  };
}

However, I remain unsure about the functioning behind this solution. It seems like postponing type inference to the subsequent function, while any neglects all further typing. Is this the expected behavior? Any recommended resources for understanding TypeScript typing better?

Answer №1

The function checkAuth allows you to define the types for req as shown below:

export function checkAuth<
  T extends express.Request,
  U extends express.Response,
  V extends express.NextFunction
>() {
  return (req: T & { params: { id: number } }, res: U, next: V) => {
    // With this setup, TypeScript recognizes the existence of the "id" property in params
    req.params.id;
    next();
  };
}

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

Is it possible to create an Arabic URL route with the use of the express web

Having trouble with getting express to render a page using an Arabic URL route: app.get('/شقق-في-لندن', function(req, res){ res.render('apartments'); }); Every time I attempt to access it through the browser a ...

What sets apart the various download options for Typescript, such as npm, NuGet, and Marketplace?

While working in VS Pro, I am a beginner developer in TypeScript (as well as React and Node...). I am focused on truly understanding how these technologies integrate and function together, rather than simply copying commands and code snippets into files. ...

Cloudinary experienced issues decoding base64 during image uploads of 1mb or greater in size

Hey there, I'm currently facing an issue while working on my React app. I can't seem to upload photos to Cloudinary using MERN stack as I keep getting the error "Could not decode base64". Just to note, I am using the free version of Cloudinary. ...

Using Angular to make an HTTP POST request to fetch data

My trusty .net backpack has been working flawlessly. However, I encountered an issue when trying to connect it with the Angular front end. All backend requests are post requests and require passing an ApiKey in the body of each request. Interestingly, ever ...

How require works in Node.js

My current database connection module looks like this: var mongodb = require("mongodb"); var client = mongodb.MongoClient; client.connect('mongodb://host:port/dbname', { auto_reconnect: true }, function(err, db) { if (err) { ...

A function's behavior will vary depending on whether it is a property of an object or not

I've been observing some peculiar behavior: In a typical scenario, TypeScript usually raises an error when an object contains too many keys, like this: type Foo = { a: string; } const a: Foo = { a: "hello", b: "foo" // Ob ...

merging JavaScript objects with complex conditions

I am attempting to combine data from two http requests into a single object based on specific conditions. Take a look at the following objects: vehicles: [ { vId: 1, color: 'green', passengers: [ { name: 'Joe', ag ...

Bring in personalized tag to TypeScript

I am working on a TypeScript file to generate an HTML page. Within this code, I want to import the module "model-viewer" and incorporate it into my project. import * as fs from "fs"; import prettier from "prettier"; import React from "react"; import ReactD ...

Can you explain the concept of being "well-typed" in TypeScript?

The website linked below discusses the compatibility of TypeScript 2.9 with well-defined JSON. What exactly does "well-typed" JSON mean? As far as I understand, JSON supports 6 valid data types: string, number, object, array, boolean, and null. Therefore, ...

Add a class individually for each element when the mouse enters the event

How can I apply the (.fill) class to each child element when hovering over them individually? I tried writing this code in TypeScript and added a mouseenter event, but upon opening the file, the .fill class is already applied to all elements. Why is this ...

Attempting to merge LowDB with the current db.json file

I'm having trouble loading an existing db.json file in lowDB. Despite following the steps outlined in the tutorial, none of the instructions seem to be working for me. const low = require("lowdb"), FileSync = require("lowdb/adapters/FileSync") ...

Working with a function in the stylesheet of TypeScript in React Native allows for dynamic styling

When attempting to use variables in my StyleSheet file, I encounter a type error even though the UI works fine. Any suggestions on how to resolve this issue? type buttonStyle = (height: number, width: string, color: string) => ViewStyle; export type St ...

Is it feasible to amalgamate the states of several child components into a single parent component state in NextJS/React?

Issue I am faced with the challenge of handling multiple Child components that can pass their state to a Parent component. Now, I am looking to render several Parent components within a Grandparent component and merge the states of each Parent into a sing ...

Exploring the differences between utilizing request.body in building RESTful APIs with Django versus Node.js

As I dive into learning the Django framework, my main aim is to leverage this knowledge in creating a rest api. Although I've looked into using django-rest framework, my current job necessitates a focus on Django specifically. In my journey so far, I ...

Utilizing Array.every to refine a union of array types, narrowing down the options

I need to narrow down the type of a variable that is a union of different array types in order to run specific code for each type. I attempted to use Array.every along with a custom type guard, but encountered an error in TypeScript stating "This expressio ...

Struggling with TypeScript compilation in a Vue.js project? Encounter error code TS2352

Here is my code snippet from window.ts import Vue from 'vue' interface BrowserWindow extends Window { app: Vue } const browserWindow = window as BrowserWindow export default browserWindow Encountering a compilation error Error message: TS2 ...

Encountering an incorrect entry in the Mongo database while attempting to modify an entry

I am currently working on a project using Node.js with Express and MongoDB. The goal is to search for and update an entry (referred to as an "event") in the database based on its unique id. The id is passed in the request body as tempEventInfoForEdit, whic ...

Why does TypeScript struggle to accurately deduce the return type when provided with certain parameter values?

I have a function that uses a switch case to return different results depending on the input. The function, called "getTimeAgo," takes in two parameters: "date" (which can be either a Date object or a string) and "mode" (which can only be either "days" or ...

Exploring ways to incorporate the context value into my component's functionality

Hi, I'm new to TypeScript and I'm facing an issue when trying to use a value I created in my context API. I keep getting the error message "Property 'sidebar' does not exist on type 'IStateContext | null'", even though it exis ...

Navigate to a nested page in React router and automatically open a new page whenever there are parameters passed

I am currently using create-react-app to build my project and I am working on implementing dynamic routing. My site has three main pages: Accordion, Movies, and MovieDetail. The Movies page displays a list of movies fetched from swapi. The goal is to have ...