I've defined the user schema using following:
import mongoose from 'mongoose'
import { Model, Schema } from 'mongoose'
import bcrypt from 'bcrypt'
enum LoginType {
EMAIL = 'email',
GOOGLE = 'google',
}
interface IUser extends mongoose.Document {
username: string
email: string
password: string
loginTypes: LoginType
comparePassword(password: string, callback: Function): Promise<Function>
}
interface IUserMethods extends Model<IUser> {
comparePassword(password: string, callback: Function): Promise<Function>
}
type UserModel = Model<IUser, {}, IUserMethods>;
const userSchema = new Schema<IUser, UserModel, IUserMethods>({
username: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
require: true,
},
loginTypes: {
type: String,
require: true,
enum: Object.values(LoginType),
},
})
/* callback = (err: Error, isMatch: any) => {} */
userSchema.methods.comparePassword = async function (
password: string,
callback: Function
): Promise<Function> {
let result
try {
result = await bcrypt.compare(password, this.password)
return callback(null, result)
} catch (err) {
return callback(err, result)
}
}
export default mongoose.model<IUser>('User', userSchema)
And calling it in the login route, but typescript shows an error Property 'comparePassword' does not exist on type '() => Promise<(Document<unknown, {}, IUser> & Omit<IUser & { _id: ObjectId; }, never>) | null>'.
on foundUser.comparePassword(req.body.password, (err: Error, isMatch: any) => {})
Following is my login route:
router.post('/credentials', (req, res) => {
/* Check if user exists in database */
const foundUser = async () => await User.findOne({ email: req.body.email })
if (!foundUser) {
res.status(401).send({ message: 'User does not exist' })
}
/* Check if password matches */
foundUser.comparePassword(req.body.password, (err: Error, isMatch: any) => {})
const jwt_token = jwt.sign(
{ name: req.body.name, email: req.body.email, id: req.body.id },
JWT_SECRET,
{ expiresIn: '10000' }
)
res.status(200).send({
name: req.body.name,
email: req.body.email,
id: req.body.id,
jwt_token: jwt_token,
})
})
I've search for it and try this solution before but not working.
While, I found
const a = new User({})
a.comparePassword(req.body.password, (err: Error, isMatch: any) => {})
will work fine just like what the mongoose docs said but not working if I use findOne
before calling comparePassword
On this line:
const foundUser = async () => await User.findOne({ email: req.body.email })
You are defining a function called foundUser
that when called will return the result of await User.findOne({ email: req.body.email })
.
As written, you would need to call the function foundUser
to actually query MongoDB. Something like:
const foundUser = async () => await User.findOne({ email: req.body.email })
const user = await foundUser();
But I think what you intended is something like this:
const foundUser = await User.findOne({ email: req.body.email })
Here foundUser
is not a function, it is the result of the MongoDB query.