Search code examples
typescriptmongooseschemamern

TypeScript Error While Using MERN Stack: Says TypeError: Invalid schema configuration: `false` is not a valid type at path `select`


I don't know what is wrong here.... im getting this error when i am trying to run my passport config for Google SignIn. This is my schema, i tried almost every solution and now, i am here.

interface userInterface{
    name : string,
    userHandle : string,
    profilePic? : string,
    following : Schema.Types.ObjectId[],
    followers :  Schema.Types.ObjectId[],
    auth : {
        signInType :string,
        sessionInfo : {
            password : string
        },
        googleInfo : {
            googleId : string,
        }
    }   
}

const userSchema = new Schema<userInterface>({
    name : {
        type : String,
        required : [true, 'Name is required.'],
        maxlength : [50 , 'Name must not exceed 50 charecters.']
    },
    userHandle : {
        type : String,
        required : [true , 'User handle is required.'],
        unique : [true, 'Please enter a unique user handle.']
    },
    profilePic : {
        type : String,
    },
    following : {
        type:  [Schema.Types.ObjectId], 
        ref : 'User'
    },
    followers : {
        type :  [Schema.Types.ObjectId], 
        ref : 'User'
    },
    auth : {
        select: false,
        signInType : {
            type : String,
            enum : ["Google" , "Session"]
        },
        sessionInfo : {
            password : {
                type : String,
                required : [function(this : any){
                    return this.auth.signInType === "Session"; 
                } , "Please enter a password."],
            }
        },
        googleInfo : {
            googleId : {
                type : String,
                required : [function(this : any){
                    return this.auth.signInType === "Google";
                }, "Please enter a google id."]
            }
        },
    },
}, {timestamps : true})

export default model<userInterface>('User' , userSchema);

This following is my passport config

import passport from "passport";
import passportGoogle from "passport-google-oauth2";
import User from "../model/UserSchema";
import {userHandleGenerater} from "../utils/utils";
const GoogleStrategy = passportGoogle.Strategy;

passport.use(
  new GoogleStrategy(
    {
      clientID: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
      callbackURL: `${process.env.FRONTEND_URI as string}/home`,
    },
    async (accessToken , refreshToken, profile , done) => {
        try{
            let user = await User.findOne({"googleInfo.googleId" : profile.id});
            if(!user){
                let userHandle = "";
                let found = true;
      
                while (found) {
                  userHandle = userHandleGenerater(profile.name.givenName);
                  let existingUser = await User.findOne({ userHandle });
                  if (existingUser) {
                    found = true; 
                  } else {
                    found = false; 
                  }
                }

                const newUser = {
                    name : profile.displayName, 
                    userHandle : userHandle,
                    auth : {
                        signInType : "Google",
                        googleInfo : {
                            googleId : profile.id
                        },
                    }
                }

                user = await User.create(newUser);
            }   
            return done(null , user);
        }catch(e){
            return done(e , null);
        }
    }
  )
);


passport.serializeUser((user : any , done) => {
    done(null , user._id);
});

passport.deserializeUser(async (id , done) => {
    try {
        const user = await User.findById(id);
        return done(null , user);
    }catch(e){
        return done(e, null);
    }
});

I am getting this error: TypeError: Invalid schema configuration: false is not a valid type at path select.I am using typescript with mern stack and i have the following packages:

  "dependencies": {
    "@types/express-session": "^1.18.1",
    "@types/node-cron": "^3.0.11",
    "@types/passport-google-oauth2": "^0.1.10",
    "backend": "file:",
    "cors": "^2.8.5",
    "express": "^4.21.2",
    "express-session": "^1.18.1",
    "mongoose": "^8.9.5",
    "node-cron": "^3.0.3",
    "passport": "^0.7.0",
    "passport-google-oauth2": "^0.2.0",
    "passport-google-oidc": "^0.1.0"
  },
  "devDependencies": {
    "@types/cors": "^2.8.17",
    "@types/express": "^5.0.0",
    "@types/node": "^22.10.7",
    "@types/passport": "^1.0.17",
    "dotenv": "^16.4.7",
    "nodemon": "^3.1.9",
    "rimraf": "^6.0.1",
    "ts-node": "^10.9.2",
    "typescript": "^5.7.3"
  }

Solution

  • I somehow found a working solution, i changed the auth object to its own schema and it somehow worked and if it works, i am not touching it. I am dropping this to help someone else who has this issue in the future.

    Here is the code:

    import { model, Schema, Document, Types } from 'mongoose';
    
    interface Auth {
      signInType: 'Google' | 'Session';
      sessionInfo?: {
        password: string;
      };
      googleInfo?: {
        googleId: string;
      };
    }
    
    interface UserInterface extends Document {
      name: string;
      userHandle: string;
      profilePic?: string;
      following: Types.ObjectId[];
      followers: Types.ObjectId[];
      auth: Auth;
    }
    
    const SessionInfoSchema = new Schema({
      password: {
        type: String,
        required: [true, 'Please enter a password.'],
      },
    }, {_id : false});
    
    const GoogleInfoSchema = new Schema({
      googleId: {
        type: String,
        required: [true, 'Please enter a Google ID.'],
      },
    }, {_id : false});
    
    const AuthSchema = new Schema({
      signInType: {
        type: String,
        enum: ['Google', 'Session'],
        required: true,
      },
      sessionInfo: {
        type: SessionInfoSchema,
        required: function (this: any) {
          return this.signInType === 'Session';
        },
      },
      googleInfo: {
        type: GoogleInfoSchema,
        required: function (this: any) {
          return this.signInType === 'Google';
        },
      },
    }, {_id : false});
    
    const userSchema = new Schema<UserInterface>(
      {
        name: {
          type: String,
          required: [true, 'Name is required.'],
          maxlength: [50, 'Name must not exceed 50 characters.'],
        },
        userHandle: {
          type: String,
          required: [true, 'User handle is required.'],
          unique: true,
        },
        profilePic: {
          type: String,
        },
        following: [
          {
            type: Schema.Types.ObjectId,
            ref: 'User',
          },
        ],
        followers: [
          {
            type: Schema.Types.ObjectId,
            ref: 'User',
          },
        ],
        auth: {
          type: AuthSchema,
          required: true,
          select: true,
        },
      },
      { timestamps: true }
    );
    
    export default model<UserInterface>('User', userSchema);