A guide on getting a mongoose document back from a function with TypeScript

There are two routes in my code that perform the same operation on a token to extract a user document from the database. Subsequently, each route carries out unique operations on this extracted document. In an effort to streamline the code, I am attempting to create a function that handles this common part of the operation and then call it within both routes. Here's a snippet of what I have in mind:

    let user = await returnUser(req, res, token)
    user.verified = true;
    await user.save();

However, I am facing an issue due to the fact that I am using Typescript. Specifically, I am encountering type errors when trying to access methods like user.save() or properties within the document. Can someone provide guidance on how to properly set up typings so that I can work with the returned document from the function without encountering these type errors?

Additional context: Below is the actual code snippet for the function that retrieves the user 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;
};

In addition, here is the link to the specific error that is being triggered:

Message when hovering over the error

And finally, here is the interface definition for 'UserDoc' which represents the structure of my user documents:

interface UserDoc extends mongoose.Document {
  email: string;
  username: string | null;
  verified: boolean;
  createdAt: Date;
}

Answer №1

The underlying issue lies in the fact that the return value of response.send() does not match the expected type UserDoc. However, your model appears to be correct from what I can see. Although I am unable to inspect the code for your Schema, we will proceed nonetheless. Let's get started:

  1. Firstly, let's examine the Schema,
// When defining a Schema, it is possible to provide a generic reference during instantiation.
// This also enhances typing with mongoose
export const UserDocSchema = new mongoose.Schema<UserDoc>({/* model */});
  1. Next, let's analyze the provided implementation. The issue arises due to the return calls for responses within the function. We will explicitly specify the return type of the function. By enforcing this return type, any errors related to returning res.send() calls will be surfaced...
import { Request, Response } from "express";
import { Token } from "../util/token";
import { User } from "../models/user";

// Instead of directly returning send responses to resolve the errors,
// we will utilize error handling which resolves the typing conundrum...
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. Now, with the function redefined as above, we will execute your function in accordance with the screenshot you shared...
router.post('user/verify', (request, response) => {
  const { token } = request.body;

  return returnUser(token)
  .then((user) => {
    // This modification ensures that the function reliably returns a user
    return response.status(200).send(user.toObject());
  })
  .catchError((error) => {
    return response.status(400).send({ error: error.message });
  });
});

UPDATE:

To import UserDoc, it must be exported here,

export interface UserDoc extends mongoose.Document {
  email: string;
  username: string | null;
  verified: boolean;
  createdAt: Date;
}

I have not yet tested this solution, but I believe it should clarify why the typings errors are being triggered by your function call...Let's hope this resolves the issue.

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

Displaying numerical data in an input field of type "number"

I'm currently working with ejs and mongodb/mongoose, attempting to render a page by passing data to an input type="number" in the value attribute, but unfortunately it's not functioning as expected. Here is the backend section of the code: Produ ...

List of nested objects converted into a flat array of objects

Looking to transform a data structure from an array of objects containing objects to an objects in array setup using JavaScript/Typescript. Input: [ { "a": "Content A", "b": { "1": "Content ...

When using setInterval, the image remains static on Safari but updates on Chrome

In my project, I am using a mock array to distribute data. One part of the project utilizes this data to display a list of cases, each with assigned images. When a case is hovered over, the images associated with that case are displayed one at a time, with ...

Evaluating models based on parameters retrieved from the database and input form

As I was working on the registration process for a client, I encountered a particular situation. The user fills out a registration form on the front end, and I process it on the backend (in JSON format). My next step is to compare this data. If a document ...

Utilizing TypeScript for Multidimensional Array Parameters

I'm currently working on JavaScript algorithms using TypeScript. Here are the functions I've created: function steamrollArray(arr: any[]): any[] { return arr.reduce( (accum: any, val: any) => Array.isArray(val) ? accum.concat(stea ...

Type of JavaScript map object

While exploring TypeScript Corday, I came across the following declaration: books : { [isbn:string]:Book}={}; My interpretation is that this could be defining a map (or dictionary) data type that stores key-value pairs of an ISBN number and its correspon ...

Safe way to implement map and spread operator in your codebase

Is there a workaround for this issue? I am working with an interface, IFoo, and an array of data IFoo[]. My goal is to map this data and modify a single property. It should look something like this const mapper = (foos: IFoo[]): IFoo[] => { return foo ...

Should Nodejs exit when an error occurs, or should it be prevented?

Currently, I am working with Nodejs on my Windows machine and I have encountered a problem. It seems that Nodejs always terminates the process when an error occurs, such as an empty Mysql insert statement. During production time and without implementing m ...

Passing a parameter to a partial view in Node.js

My route configuration is as follows: app.get('/Search', function (req, res) { var searchString = req.query.SearchString; var request = require('./cstapi')(searchString, onBody); function onBody(body) { res.render(&apos ...

Comparing Angular global variables: when to use static readonly in service class versus const

Which method is the better choice? @Injectable({ providedIn: 'root' }) export class MyService { static readonly VALIDITIES = new Map<number, string>([ ... ]); ... } OR: const Validities = new Map<number, string>([ .. ...

retrieving information from an array nested within a JSON object in an Angular application

I am struggling to retrieve two specific values from a JSON object. The content of the JSON is as follows: [ { "type":"session_start", "properties":[ { "property":"activity&q ...

Retrieve the most recently added value using a Sequelize query

Utilizing Sequelize for database operations, I have a table called status_config which includes a column named created_time with data type timestamp (2021-06-02 12:04:52.293977). My current task is to query this table and retrieve the most recent entry. ...

Loading an external javascript file dynamically within an Angular component

Currently, I'm in the process of developing an Angular application with Angular 4 and CLI. One of my challenges is integrating the SkyScanner search widget into a specific component. For reference, you can check out this Skyscanner Widget Example. T ...

Issues with Angular ng-bootstrap tabset component not functioning as expected

{ "name": "ModalWindow", "version": "1.0.0", "repository": { "type": "git", "url": "" }, "scripts": { "build": "webpack --mode production", "start": "webpack-dev-server --mode development --open" }, "license": "MIT", "depend ...

Steps for creating a table with a filter similar to the one shown in the image below

https://i.sstatic.net/zR2UU.png I am unsure how to create two sub-blocks within the Business A Chaud column and Potential Business Column. Thank you! I managed to create a table with input, but I'm struggling to replicate the PUSH & CtoC Column for ...

Is there a method or alternative solution for deconstructing TypeScript types/interfaces?

Imagine a scenario where a class has multiple type parameters: class BaseClass<T extends T1, U extends U1, V extends V1, /* etc. */ > Is there a method to consolidate these type arguments in a way that allows for "spreading" or "destructuring," sim ...

Creating a custom pipe that converts seconds to hours and minutes retrieved from an API can be achieved by implementing a transformation function

Can someone please provide guidance on creating a custom pipe in Angular 8 that converts seconds to hours and minutes? Thank you. <div class="col-2" *ngFor="let movie of moviesList"> <div class="movie"> {{ movie.attributes.title }} ...

Tips on Identifying the Category

I am currently studying TypeScript. Recently, I have been using Axios to fetch API data, and then I stored the returned value in a useEffect hook. However, when trying to display it on the screen, I encountered an error stating that there is no 'name ...

The Nextjs next-auth implementation with URL '/api/auth/callback/cognito' encountered a 502 Bad Gateway error while in production

I'm facing a challenge while trying to deploy a nextjs app that utilizes 'next-auth' with AWS Cognito. Interestingly, the app runs smoothly when tested locally using either next dev or next start. However, upon deploying it on the producti ...

Trouble with image uploads on the Express.js platform

Within my application, I've encountered an issue with uploading images to the public/images folder. Previously, everything was functioning properly, but now I'm facing a problem. Although I receive a success message indicating that the image has ...