5

I am currently converting my API from JS to TS. However, I'm having some difficulties with mongoose & typescript. Specifically, this is not available inside my instance methods.

My code:

AccountSchema.methods.comparePassword = async function (candidatePassword: string) {
  const isMatch = await bcrypt.compare(candidatePassword, this.password);
  return isMatch;
};

Which generates the following error as this refers to the function rather than the actual document:

Argument of type 'Function' is not assignable to parameter of type 'string'.

However, according to Mongoose's documentation, there shouldn't be an error as this should refer to the actual document.

What this actually refers to:

this: {
    [name: string]: Function;
}

How I defined my schema:

const AccountSchema = new mongoose.Schema<IAccount>({...})

My approach worked just fine with JS, so I know it has something to do with TypeScript. Mongoose documentation confirms that my implementation is the right way to define instance methods, so I'm quite confused why it doesn't work.

Is there a specific TS way of declaring & using instance methods in mongoose that I don't know of?

Any help would be greatly appreciated!

linus_hologram
  • 1,595
  • 13
  • 38
  • *"Argument of type 'Function' is not assignable to parameter of type 'string'."* is pretty clearly telling you you're passing a function where a string is expected. What argument is the error on? What is the definition of the function/method you're calling? What is the definition of the argument? – T.J. Crowder Jan 13 '21 at 15:19
  • May be try the shorthand.AccountSchema.methods.comparePassword = async (candidatePassword: string): boolean => { const isMatch = await bcrypt.compare(candidatePassword, this.password); return isMatch; }; – user906573 Jan 13 '21 at 15:20
  • @T.J.Crowder there shouldn't even be such an error in the first place, as "this", according to Mongoose's documentation, should refer to the actual document rather than the function – linus_hologram Jan 13 '21 at 15:21
  • @user906573 that doesn't work as it prevents this from being bound (according to Mongoose's docs. I receive an error message that "this" is possibly undefined. – linus_hologram Jan 13 '21 at 15:23
  • @T.J.Crowder updated my question, should be more clear now – linus_hologram Jan 13 '21 at 15:28
  • Is this a run time or compilation error? Also, is there a reason why the bcrypt.compare call is async / await? – user906573 Jan 13 '21 at 15:34
  • @user906573 a compilation error – linus_hologram Jan 13 '21 at 15:36
  • Ok. I have this code in vs code and it compiles ok...export const AccountSchema = new Schema({ password: { type: String, required: true } }); AccountSchema.methods.comparePassword = function (candidatePassword: string): boolean { const isMatch: boolean = this.password === candidatePassword; return isMatch; }; This is the version for my npm packages: "mongoose": "5.11.8" "typescript": "4.1.3" – user906573 Jan 13 '21 at 15:37
  • @user906573 hmmm any guesses why I receive this error? – linus_hologram Jan 13 '21 at 15:38
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/227287/discussion-between-user906573-and-linus-hologram). – user906573 Jan 13 '21 at 15:41
  • Cannot. Sorry. Behind corporate proxy. – user906573 Jan 13 '21 at 15:42

1 Answers1

6

All I needed was a this parameter on that function. That's special in TS, and specifies the type of this within the function.

Like so:

async function (this: IAccount, candidatePassword: string) { ... }

this parameters are not passed explicitly, so the new parameter doesn't change how the function is called.

linus_hologram
  • 1,595
  • 13
  • 38
  • [`this` is a special keyword](https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) in JS. So I'd recommend **not** using the variable `this` and use some other variable. – Liam Oct 19 '21 at 08:33