Reputation: 15
I have two routes that do the same operation on a token to extract a user document from the database. After that, both perform different operations on that document. To improve the code, I am trying to put that same operation part in a function and call it in both routes. Something like -
let user = await returnUser(req, res, token)
user.verified = true;
await user.save();
But the problem is I am using Typescript and I am getting type errors when doing something like user.save() or accessing the items in the document. Can anyone tell me how do I set up the types so that I can access the document returned from the function without getting type errors.
Edit: I am adding the code. The function that will be returning a document -
import { Request, Response } from "express";
import { Token } from "../util/token";
import { User } from "../models/user";
export const returnUser = async (
req: Request,
res: Response,
token: string
) => {
if (!token) return res.status(400).send({ error: "Token is not present" });
let decoded = await Token.decode(token);
if (decoded === false) {
return res.status(400).send({ error: "Invalid Token" });
}
let email = decoded.email;
let user = await User.findOne({ email });
if (!user) return res.status(400).send({ error: "User not found" });
if (user.createdAt.getTime() !== decoded.epoch)
return res.status(400).send({ error: "Invalid timestamp" });
return user;
};
And the error -
Message when hovering over the error
my UserDoc -
interface UserDoc extends mongoose.Document {
email: string;
username: string | null;
verified: boolean;
createdAt: Date;
}
Upvotes: 1
Views: 2746
Reputation: 1560
the cause of the problem is that you are returning response.send()
, which does not have type UserDoc
, but as far as i could tell you're model is right. I cant see the code for your Schema
but we will address it anyhow. So let us begin:
Schema
first,// a schema definition does accept a generic reference when instantiating it.
// this also adds better typings with mongoose
export const UserDocSchema = new mongoose.Schema<UserDoc>({/* model */});
res.send()
calls...import { Request, Response } from "express";
import { Token } from "../util/token";
import { User } from "../models/user";
// so to stop the return errors we will instead of return send responses
// we will take advantage of the error handling situation which will fix
// the typing dilemma...
export const returnUser = async (token: string): Promise<UserDoc> => {
if (!token) throw Error("Token is not present");
let decoded = await Token.decode(token);
if (decoded === false) {
throw Error("Invalid Token");
}
let email = decoded.email;
let user = await User.findOne({ email });
if (!user) throw Error("User not found");
if (user.createdAt.getTime() !== decoded.epoch)
throw Error("Invalid timestamp");
return user;
};
router.post('user/verify', (request, response) => {
const { token } = request.body;
return returnUser(token)
.then((user) => {
// this way this function is guaranteed to return a user
return response.status(200).send(user.toObject());
})
.catchError((error) => {
return response.status(400).send({ error: error.message });
});
});
UPDATE:
to import UserDoc you will have to export it here,
export interface UserDoc extends mongoose.Document {
email: string;
username: string | null;
verified: boolean;
createdAt: Date;
}
I haven't had the chance to test this but I think it should explain why your function call is making the typings error suggestions...Hope this works out
Upvotes: 4