Issue with Typescript in mongoose schemas' pre method: Surprising assignment of 'this' to local variable

I'm currently working on setting up authentication using MongoDB and NestJS for an Ionic application. After sending a POST request to the api/users route, I encountered the following error message:

[Nest] 85372 - 03/26/2020, 14:04:49 [ExceptionsHandler] Cannot read property 'password' of undefined +23790ms

In my users.schema.ts file, I came across this error message:

Unexpected aliasing of 'this' to local variable.eslint(@typescript-eslint/no-this-alias)

The snippet from my users.schema.ts file where the error occurs is as follows (the problematic line is commented out):

import * as mongoose from 'mongoose';
import * as bcrypt from 'bcryptjs'

export const UserSchema = new mongoose.Schema({
    email: {
        type: String,
        unique: true,
        required: true
    },
    username: {
        type: String,
        unique: true,
        required: true
    },
    password: {
        type: String,
        unique: true,
        required: true
    },
    createdAt: {
        type: Date,
        default: Date.now
    },
    updatedAt: {
        type: Date,
        default: Date.now
    }
});

UserSchema.pre('save', function (next) {
    const user = this; // This is marked as an error in vs code
    if (!user.isModified('password')) return next();

    bcrypt.genSalt(10, (err, salt) => {
        if (err) return next(err);
        bcrypt.hash(this.user.password, salt, (err, hash) => {
            if (err) return next();
            this.user.password = hash;
            next();
        });
    });
});

UserSchema.methods.checkPassword = (attempt, callback) => {
    bcrypt.compare(attempt, this.user.password, (err, isMatch) => {
        if (err) return callback(err);
        callback(null, isMatch);
    })
}

When attempting to use an arrow function for the same schema, I faced another error message after sending a POST request to api/users:

[Nest] 85947 - 03/26/2020, 14:09:30 [ExceptionsHandler] Cannot read property 'isModified' of undefined +22567ms

UserSchema.pre('save', (next) => {
    if (!this.user.isModified('password')) return next();

    bcrypt.genSalt(10, (err, salt) => {
        if (err) return next(err);
        bcrypt.hash(this.user.password, salt, (err, hash) => {
            if (err) return next();
            this.user.password = hash;
            next();
        });
    });
});

What could be the issue here?

Answer №1

Arrow functions should be avoided as they can lead to losing track of the this keyword. It is recommended to refer to the official documentation for arrow functions, which provides insightful examples on understanding "this" in an arrow function context. Check out MDN Arrow function expressions

There are a couple of solutions:

Option 1: Omit the arrow-function callback for bcrypt

UserSchema.pre('save', function (next) {
  if (!this.isModified('password')) return next();

  bcrypt.genSalt(10, function (err, salt) {
    if (err) return next(err);
    bcrypt.hash(this.user.password, salt, (err, hash) => {
      if (err) return next();
      this.user.password = hash;
      next();
    });
  });
});

Option 2: Disable eslint rule and consistently use the user variable

UserSchema.pre('save', function (next) {
  const user = this;
  if (!this.isModified('password')) return next();

  bcrypt.genSalt(10, (err, salt) => {
    if (err) return next(err);
    bcrypt.hash(user.password, salt, (err, hash) => {
      if (err) return next();
      user.password = hash;
      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

What is the process for setting up a MongoDB database using Node.js?

Currently, I have a functional web app that utilizes a MongoDB database. This app is capable of fetching and posting information to the database that is running on a localhost. const db = monk('localhost/datbaseName') //create/connect to datab ...

What is the process for accessing my PayPal Sandbox account?

I'm having trouble logging into my SandBox Account since they updated the menu. The old steps mentioned in this post Can't login to paypal sandbox no longer seem to work. Could someone please provide me with detailed, step-by-step instructions o ...

Retrieve PDF files from .Net Core Web API using Angular

I've been struggling with this issue for several days now. Despite searching through many threads on Stackoverflow, I couldn't find a solution that worked for me. Below is the Web API code meant to return a simple PDF file: [HttpGet("pd ...

What is the best way to implement forwardRef in a distinct select component?

Currently, I am utilizing react, typescript, and styled-components to work on my project. Specifically, I am aiming to create a select component for use in React Hook Form. Initially, everything seemed to be in order, but I encountered an error from typesc ...

This code cannot be called as a function, Every individual in the union

My approach has been aligned with the current architecture, focusing on reducing complexity as much as possible. I have strived for the best possible outcome, but encountered a single failed test along the way. After three days of struggling, I'm cl ...

How can I transform seconds since epoch into Datetimes in MongoDB?

How can I convert seconds after epoch to Datetimes in MongoDB query? I need a solution similar to the Python function below: In [10]: datetime.utcfromtimestamp(1000000000) Out[10]: datetime.datetime(2001, 9, 9, 1, 46, 40) I wish I could insert datetimes ...

"Implemented a fresh pathway within the app-routing.module.ts file, but unfortunately, ngxAdmin is experiencing functionality issues

While customizing the ngx-admin template, I attempted to incorporate a new module into the app module and added its route in app-routing.module.ts. However, upon trying to open it, the module seems to be stuck at loading without any errors appearing in the ...

Issue encountered while trying to update form data in mongoDB with nodejs

The post delete options are functioning correctly, but the put operation is not working as expected. It updates successfully, however with function String() { [native code] } values. controller.ts router.put('/:id', (req,res)=> { if (!Ob ...

What is the best way to link to a different module in typescript?

Encountering an issue related to the import and module features in TypeScript version 2.4.1. The problem arises from having two separate files: testAdd.ts: module mymodule { export class myClassAdd { static add(left: number, right: number): n ...

Fixing the Access Denied Issue in Next.js 13.4 with the Help of NextAuth Google Login and MongoDB

Currently, I am working on integrating Google login with Next Auth in Next.js version 13.4. My issue arises when I attempt to log in using Google; it redirects me to the following Google page link: "http://localhost:3000/api/auth/signin?callbackUrl=http%3A ...

Converting a String variable to a String Literal Type in Typescript: A step-by-step guide

When working with Typescript, imagine I need to call a function that has the following signature- function foo(param: "TRUE"|"FALSE"|"NONE") Is there a way to achieve something like this- var str = runtimeString() if(str === "TRUE" | str === "FALSE" | s ...

What is the method for retrieving an attribute's value from an object that does not have key-value pairs?

My current project involves working with dynamoose and running a query that produces the following output: [ Document { cost: 100 }, lastKey: undefined, count: 1, queriedCount: undefined, timesQueried: 1 ] When I use typeof(output), it returns O ...

What is the best way to combine various express routes from separate files in a TypeScript project?

After transitioning to TypeScript, I have been facing issues with merging different routes from separate .ts files. In JavaScript, I used to combine routes like this: app.use("/users/auth", require("./routes/user/auth")); app.use("/users", require("./rou ...

Camera Capacitor designed to eliminate popup notifications

I am utilizing Angular along with the camera plugin in Capacitor to locally save images on both desktop and tablets. I aim to utilize the CameraSource to directly access the camera or open the gallery for files without displaying a prompt. This is how my ...

What is the best way to insert a value into a MongoDB document using a for loop?

I am looking to save each day of the year in the Mongo Database but I'm unsure about the best approach. I have tried using the $push method and .update method, however, neither seem to be suitable for this scenario. This is my controller: exports.re ...

Building a Rails API using Mongoid within a custom local gem

Currently, I am working on a rails-api project that utilizes my custom local gem for handling authorization. This specialized gem requires a connection to MongoDB in order to securely store user data and authentication tokens. Unfortunately, I have encoun ...

Angular 2 - Initiating a function in a child component from its parent

While it's common to send data from a parent component to a child using @Input or call a method on the parent component from the child using @Output, I am interested in doing the opposite - calling a method on the child from the parent. Here is an exa ...

When using `mongodb`'s `printjson` function, be aware that the output may include an `ObjectId`

When executing my mongo shell script, the command looks like this: mongo --quiet myscript.js > /tmp/my.json In myscript.js, I utilize printjson. When using mongodb printjson, it outputs ObjectId to my.json, for example: "_id" : ObjectId("5444a932ca62 ...

Managing individual HTTP responses within Angular 6

I currently have 15 HTTP requests being sent to the API individually. Instead of waiting for all requests to finish processing (especially one that can take a few minutes), I want to handle responses as they come in. On the service side: findOneByOne ...

Incorporating Azure Active Directory with Ionic

We are exploring the possibility of expanding our Angular Web Application to a Mobile Application using the Ionic framework. Upon reviewing the official documentation at https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc, we ...