Leveraging union types in Mongoose and typescript: Accessing data from a populated field with multiple value options

In my codebase, I have the following models:

CoupleModel.ts

import mongoose, { Model, Schema } from 'mongoose';
import { CoupleType } from '../types/coupleTypes';

const coupleSchema = new Schema(
    {
        user1: {
            type: Schema.Types.ObjectId,
            ref: 'User',
            required: true,
        },
        user2: {
            type: Schema.Types.ObjectId,
            ref: 'User',
            required: true,
        },
    },
    {
        timestamps: true,
    }
);

export default coupleSchema;
const Couple: Model<CoupleType> = mongoose.model<CoupleType>('Couple', coupleSchema);

UserModel.ts

   import mongoose, { Model, Schema } from 'mongoose';
    import { UserType } from '../types/userTypes';
    
    const userSchema = new Schema(
        {
            name: {
                type: String,
                required: true,
            },
            email: {
                type: String,
                required: true,
                match: [/^\S+@\S+\.\S+$/, 'Please use a valid email address.'],
            },
        },
        {
            timestamps: true,
        }
    );
    
    const User: Model<UserType> = mongoose.model<UserType>('User', userSchema);
    
    export default User;

Additionally, I have defined these types:

userType.ts

import { Document } from 'mongoose';

export type UserType = Document & {
    name: string;
    email: string;
};

coupleType.ts

import { Document, Types } from 'mongoose'; import { UserType } from './userTypes';

export type CoupleType = Document & {
    user1: Types.ObjectId | UserType;
    user2: Types.ObjectId | UserType;
};

To handle different operations, I declared user1 and user2 with the type Types.ObjectId | UserType:

  1. If it's couple.find(), they will be of type Types.ObjectId
  2. If it's
    couple.find().populate(['user1','user2'])
    , they will be of type UserType
  3. In the couple.create({user1,user2}), they will be of type Types.ObjectId

However, I encountered an issue:

  const couples = await Couple.find().populate('user1').populate('user2');

    const emailPromises = couples.map(async (couple) => {
      const { user1, user2 } = couple;
      console.log("🚀 ~ emailPromises ~ user1.email:", user1.email)
      console.log("🚀 ~ emailPromises ~ user2.email:", user2.email)
    });

Due to TypeScript not automatically inferring the type of user1 and user2 as UserType, this error occurs:

Property 'email' does not exist on type 'ObjectId | UserType'.
  Property 'email' does not exist on type 'ObjectId'.ts(2339)

How can I resolve this issue?

Answer â„–1

I opted to utilize typeguard:

export const isUserType = (user: Types.ObjectId | UserType): user is UserType => {
    return (user as UserType).email !== undefined;
}


  if (user1 && isUserType(user1)) {
  }

Instead of using type casting:

  const user1 = couple.user1 as UserType;

However, relying on type casting is a more risky approach since it may lead to runtime errors if the returned data does not match the structure of UserType due to issues such as populate mishaps.

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

Accessing app state in angular guard using NGRX - What is the procedure?

In my route guard(canActivate), I am looking to access the current state of my app in order to validate data and prevent users from navigating incorrectly. How can I retrieve the current state? I attempted using a subscription on the store to obtain the s ...

Angular Error: Property 'map' is not found in type 'OperatorFunction'

Code: Using map and switchMap from 'rxjs/operators'. import { map, switchMap } from 'rxjs/operators'; Here is the canActivate code for route guard: canActivate(): Observable<boolean> { return this.auth.userObservable ...

Learn the proper way to specify the return type of a function as a class, rather than an instance, in Typescript

Is there a way to declare that a function returns a generic class definition? I have tried the following for non-generic classes, but it does not work for generic ones: export function composeAll(composeFunction: Function, depsFunction: Function): (compon ...

Error: Unable to access the 'map' property of an undefined object......Instructions on retrieving a single post

import React,{useEffect, useState} from 'react' //import {Link} from 'react-router-dom' import { FcLikePlaceholder, FcComments } from "react-icons/fc"; const SinglePost = () => { const [data,setdata] = useState([]) co ...

Transferring Data from MongoDB to Teradata

In our efforts to transfer data from MongoDB to Teradata (DW), we anticipate the need for data transformations. I am seeking assistance with the following queries to aid in the development of a migration solution: What is the most efficient format for e ...

Tips for dynamically adapting PATCH method content

Currently, while working on developing a REST API using NodeJS, ExpressJS, and Prisma, I encountered the following approach when updating a user using the PATH method: const data = {} if (req.body.email != null) data.email = req.body.email if (req.bod ...

Detect when a child li element is clicked and then toggle the class of its parent div

I have a div container that contains an unordered list tab menu. By clicking on each tab, the menu content changes correspondingly. The functionality is working well, but I want to alter the background image of the container div based on which li is clicke ...

Passing parameters from JavaScript to a PHP class and sending the response back to JavaScript: A comprehensive guide

I am attempting to utilize a PHP Class along with JavaScript, but I need to adjust the class in order to pass a parameter to it. Since my knowledge of PHP is limited, I am unsure how to accomplish this. The class provided below uses a static variable $si ...

Transitioning from MUI v4 to v5: Issue with declaring module "@mui/styles/defaultTheme"

While working on migrating from MUI v4 to MUI v5 following Material-U's instructions, I encountered the troubleshooting issue where Property "palette", "spacing" does not exist on type 'DefaultTheme.' To resolve this problem, I referred to ...

Maximizing performance: optimizing Javascript usage in .net Web Application

After completing a web application using C#, ASP, and some javascript, my main page is cluttered with a mix of javascript/jQuery at the bottom. I have several ajax calls to web methods in this mess. Is there a way to organize this javascript into multipl ...

Halt and anticipate a boolean reply from another function

Is there a way to create two functions in JavaScript, run one of them, then within that function, execute the other and pause until it receives a response (yes or no) before moving on to an if statement? The user's response should be manual. Here is ...

Measuring the variable size of an array containing objects of a given class

Recently, I created a basic code/userscript to receive notifications about any changes on a specific website: function notifier(){ setTimeout(function () { location.reload(true); },60000) } function notiCounter() { console.log("Cou ...

Creating dynamic properties in a JavaScript object literal is a great way to customize

I am encountering an issue where I am trying to define input values from an HTML page as properties of a JavaScript Literal object, but I keep getting an error stating Undefined when I try to access it in the JS file. For example, if I have an input value ...

Overflow of Primary Text in Material UI List Item

I apologize if this question has already been asked, but I have searched and couldn't find the solution! I am facing an issue with a Material UI listview that has a fixed width within a sidebar. The titles of some options are not properly rendering a ...

The click event is failing to trigger because of the alteration in the width of the table cell

I've encountered a unique issue - I'm working with a <table> where each <td> contains a text box as well as an add button in the following cell. The text box includes an onblur function that hides the textbox and generates a <span& ...

Issues with grunt - Alert: Task "ngAnnotate:dist" has encountered an error. Proceed using --force option

Encountering an unexpected issue with a Grunt task that previously ran smoothly. The error message is as follows: Running "ngAnnotate:dist" (ngAnnotate) task Generating ".tmp/concat/scripts/scripts.js" from: ".tmp/concat/scripts/scripts.js"...ERROR >& ...

Decode the URL using JavaScript or JQuery

Is there a quick and efficient way to decode a URL using JavaScript or JQuery? For example: Consider the following URL: http://localhost:8080/map/file.html?var1=a%20b%20c&var2=d%20e%20f If we use the code snippet below, var str = "var1=a%20b% ...

JS: The for loop will keep iterating even if the condition becomes false

Can anyone help me understand why my for loop is continuing even after the conditions are met? Unfortunately I can't share the entire file due to its size, but here is a snippet of the loops: for (var j = 0; j < depKeyArr.length; j++) { var di ...

Sending an Ajax request using an array of parameters and then accessing them in PHP

I have created a JavaScript function that facilitates AJAX posts by accepting an array of parameters. The function is outlined below: /** * A quick function to execute an AJAX call with POST method and retrieve data in JSON format * @param {string} url - ...

Tips on hiding the checkbox within the Material UI TextField input when using MenuItems with checkboxes

I've customized the MenuItems in a TextField of type Select to include checkboxes. However, when I select an item from the menu, the checkbox is also displayed in the input field of the TextField. Requirement: I want to hide the checkbox in the TextF ...