41x3n
41x3n

Reputation: 15

How to return a mongoose document from a function using typescript

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

Answers (1)

bloo
bloo

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:

  1. let us consider the 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 */});
  1. now let us look at the implementation provided. the error is caused by the returning response calls in the function, so will define an explicit return type on the function. making the function return this type will give the type errors where you are returning the 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;
};
  1. so now with the function the way it is, we will call your function like so based on the screenshot you provided...
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

Related Questions