The user's type from express-session is not being properly detected by Typescript

I have a process where I retrieve the user object from the database and set it on the express-session:

export const postLogin = async (
    request: Request,
    response: Response,
    next: NextFunction
): Promise<void> => {
    try {
        request.session.user = await UserModel.findById('6127bd9d204a47128947a07d').orFail().exec()
        response.redirect('/')
    } catch (error) {
        next(error)
    }
}

After setting the user object, I attempt to use the Mongoose method populate() on the user object to retrieve its associated cart:

export const getCart = async (
    request: Request,
    response: Response,
    next: NextFunction
): Promise<void> => {
    try {
        const userWithCartProducts = await request.session.user.populate('cart.items.productId').execPopulate()
    } catch (error) {
        next(error)
    }
}

However, during this process, I encounter an error stating:

TypeError: request.session.user.populate is not a function

To address this issue, I defined a custom user type within express-session as shown below:

declare module 'express-session' {
    interface SessionData {
        user?: DocumentType<User>
    }
}

In the definition of user, I utilized DocumentType<User> as I am using Typegoose for typing my models. I'm uncertain if this approach is appropriate for Typegoose.

If anyone has insights into what might be causing the error or suggestions for improvement, your input would be highly valued.

Answer №1

An issue arises when the `user` object within the `session` object is fetched by the `MongoDBStore`. The `MongoDBStore` lacks awareness of the `User` model defined in Typegoose, resulting in only raw data being retrieved from the session database, excluding the methods specified in the Typegoose model.

To resolve this, upon a new request, following the initialization of express-session, it is imperative to retrieve the user once from the database and integrate it into the `request` object through a middleware as shown below:

app.use(initializeUser)

export const initializeUser = async (request: Request, response: Response, next: NextFunction): Promise<void> => {
    try {
        request.user = await User.findById(request.session.user._id).orFail().exec()
        next()
    } catch (error) {
        next(error)
    }
}

In order to specify the `User` model for Typegoose, define it on the `Request` like so:

declare global {
    declare namespace Express {
        export interface Request {
            user?: DocumentType<User>
        }
    }
}

As explained earlier, even though the `user` object is stored in the `session` during the `login` route, the request concludes there and the session (along with the `user` object) is saved to the database. Subsequently, when a new `request` is made, the `user` object present in the `session` is fetched by the `MongoDBStore`, without recognizing the `User` Model or the Typegoose-defined methods. This process rectifies that issue. It is also applicable in Javascript with Mongoose.

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

The Angular Component utilizes the ng-template provided by its child component

I am currently facing an issue that involves the following code snippet in my HTML file: <form-section> <p>Hello</p> <form-section> <ng-template test-template> TEST </ng-template> ...

The power of Ionic 2 combined with the Web Audio API

I am currently developing an Ionic 2 application that requires access to the user's microphone. When working on a web platform, I would typically use the following code snippet to obtain microphone access. navigator.getUserMedia = (navigator['ge ...

Tips for transforming a Json array into an object in Angular 5

I am working with a Json array that looks like this: [{"name":"ip","children":{"label":"ip","value":"","type":"text","validation":"{ required: true}"}} ,{"name":"test","children":{"label":"test","value":"","type":"text","validation":"{ required: true}"}} ...

What is the best way to add data to my collection using the main.js file on the server side in a Meteor application

I am a beginner with Meteor and trying to customize the tutorial codes. I have a code that listens for packets on my server-side main.js. Now, I need to store the data printed on the console into my database collection. import { Meteor } from 'meteor/ ...

Importing in ES6/Typescript: combine imports with names onto a single line

Is it possible to condense this code into a single line? import * as Express from 'express'; import { Application, NextFunction, Request, Response } from 'express'; Signed, Dan the Dev ...

Guide to retrieving account information from a MySQL database

I am currently developing a web application utilizing a three-tier architecture with express and docker. I am integrating mysql as the database to store user accounts. Below is my initialize-database.sql file: CREATE TABLE accounts( personId INT NOT N ...

Retrieve data from a URL using Angular 6's HTTP POST method

UPDATE: Replaced res.json(data) with res.send(data) I am currently working on a web application using Angular 6 and NodeJS. My goal is to download a file through an HTTP POST request. The process involves sending a request to the server by calling a func ...

What is the process for running raw queries in the Jenssegers Mongodb ORM for Laravel?

I am currently using Laravel in conjunction with the jessenger mongodb library (https://github.com/jenssegers/laravel-mongodb), and within my mongodb database, I have two object collections: User: (id, name, email) and Message: (from_id, to_id, text) I ...

Using arrays in the request body with Node.js Express framework

Trying to include an array in the request body for a POST call to MongoDB, aiming to insert a new document upon success. See my current code snippet below: app.post(`/api/add`, async (req, res) => { collection.create({ 'id': req.body.id, ...

Opt for Observable over Promise in your applications

I have implemented this function in one of my servlets: private setValues() { this.config.socket.on('config.weather', (values:any) => { console.log(values); } However, I would like to refactor it to something like this: private se ...

Issue with array push not working within nested Promise

I recently encountered an issue with my Express API route that retrieves an artist's details along with an array of releases for that artist. My current goal is to iterate over this array, extract each URL, and then make additional API calls to retri ...

Retrieve numerous records that correspond to the most recent date using a solitary MongoDB query in Mongoose

I have a MongoDB query here. How can I optimize this query for Mongoose? db.logs.find({date: db.logs.find({}, {date:1,"_id":0}).sort({date:-1}).limit(1).toArray()[0].date}) There may be multiple documents with the same date and we want to fetch all the ...

Obtain the parameters of a function within another function that includes a dynamic generic

I am attempting to extract a specific parameter from the second parameter of a function, which is an object. From this object, I want to access the "onSuccess" function (which is optional but needed when requested), and then retrieve the first dynamic para ...

Encountered an issue when attempting to add a product to the cart. TypeError: Unable to access the 'push' property of an undefined object

When a user clicks on the "add to cart" button for a particular product, I am trying to push the product details into the cart model. However, an error is being displayed: TypeError: Cannot read property 'push' of undefined Below is the route fi ...

Guide to utilizing @types/node in a Node.js application

Currently, I am using VSCode on Ubuntu 16.04 for my project. The node project was set up with the following commands: npm init tsc --init Within this project, a new file named index.ts has been created. The intention is to utilize fs and readline to read ...

Increasing the number of service providers in Angular2-4 directives

Is there a way to apply both * to a string? Below is the code snippet I am working with: <a class="sidenav-anchor" *ngIf="!item.hasSubItems()" md-list-item md-ripple [routerLink]="[item.route]" routerLinkActive="active" [routerLinkActiveOptions]="{ex ...

How can I move the cursor to the beginning of a long string in Mat-autocomplete when it appears at the end?

I'm struggling to figure out how to execute a code snippet for my Angular app on Stack Overflow. Specifically, I am using mat-autocomplete. When I select a name that is 128 characters long, the cursor appears at the end of the selected string instead ...

Is it possible to add data in MongoDB without specifying a field name?

I have a couple of queries that revolve around the same concept: If I want to insert a new 'row' in MongoDB, can I do so by specifying the order of the fields? For instance, if my collection looks like items = { { name: "John", age: "28" ...

Color-Thief Node plugin reported an issue: "The provided image has not finished loading."

While working in Node/Express, I attempted to utilize the npm package color-thief to extract the dominant color from an image. Unfortunately, it failed with the error message stating that the "image given has not completed loading". The intriguing part is ...

Typing should be positioned on either side of the declaration

When I define the type MyType, it looks like this: export type MyType = { ID: string, Name?: string }; Now, I have the option to declare a variable named myVar using three slightly different syntaxes: By placing MyType next to the variable ...