asobirov
asobirov

Reputation: 572

Next.js + Typescript + mongoose error when using `let cached = global.mongoose`

I was trying to created a cached mongoose connection for Next.js + Typescript app, but using:

let cached = global.mongoose;

if (!cached) {
  cached = global.mongoose = { conn: null, promise: null };
}

global.mongoose is showing the following Error:

Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.ts(7017)

EDIT: here's full /lib/dbConnect.ts file

import mongoose, { Connection } from "mongoose";

const MONGODB_URI: string = process.env.MONGODB_URI!;

if (!MONGODB_URI) {
  throw new Error(
    "Please define the MONGODB_URI environment variable inside .env.local"
  );
}

let cached = global.mongoose;

if (!cached) {
  cached = global.mongoose = { conn: null, promise: null };
}

async function dbConnect() {
  if (cached.conn) {
    return cached.conn;
  }

  if (!cached.promise) {
    const opts = {
      bufferCommands: false,
    };

    cached.promise = mongoose.connect(MONGODB_URI, opts).then((mongoose) => {
      return mongoose;
    });
  }
  cached.conn = await cached.promise;
  return cached.conn;
}

export default dbConnect;

Upvotes: 3

Views: 3111

Answers (5)

chip-drop
chip-drop

Reputation: 1

Adding onto Alisson Leal's answer, declaring mongoose as follows seems to be working for me:

// the namespace conflicts, so import as 'mg'
import { default as mg } from 'mongoose';

declare global {
  var mongoose: {
    conn: null | typeof mg;
    promise: null | Promise<typeof mg>;
  };
}

Upvotes: 0

Guilherme Lima
Guilherme Lima

Reputation: 109

Quick and easy solution!

This connection file is based on an official Next.Js example on GitHub.

The project is able to connect to mongodb using the mongoose library. However, he does not provide an example of how to do this in TypeScript. But easily you can convert the example code which will work normally without any hassle of needing to declare types in utils/global.d.ts and so on.

1 First install mongoose and its flavors.

To install "mongoose" in a TypeScript project in Next.js, follow these steps:

1 - Open the terminal at the root of your project.

2 - Run the following command to install "mongoose":

# if you are using npm
npm install mongoose

# if you are using yarn
yarn add mongoose

3 - Run the following command to install the "mongoose" types:

# se estiver usando npm
npm install --save-dev @types/mongoose


# se estuver usando yarn
yarn add --dev @types/mongoose

2 Create the TypeScript connection file dbConnect.ts.

import mongoose from 'mongoose';

const MONGODB_URI: string | any = process.env.MONGODB_URI;

if (!MONGODB_URI) {
  throw new Error('Please define the MONGODB_URI environment variable inside .env.local');
}

/**
 * Global is used here to maintain a cached connection across hot reloads
 * in development. This prevents connections growing exponentially
 * during API Route usage.
 */
let cached = (global as any).mongoose;

if (!cached) {
  cached = (global as any).mongoose = { conn: null, promise: null };
}

async function dbConnect() {
  if (cached.conn) {
    return cached.conn;
  }

  if (!cached.promise) {
    const opts = {
      bufferCommands: false,
    };

    cached.promise = mongoose.connect(MONGODB_URI, opts).then((mongoose) => {
      console.log('Connected to database!');
      return mongoose;
    });
  }

  try {
    cached.conn = await cached.promise;
  } catch (e) {
    cached.promise = null;
    throw e;
  }

  return cached.conn;
}

export default dbConnect;

Upvotes: 0

Anthony Nguyen
Anthony Nguyen

Reputation: 86

As Prisma link:

Create a new file utils/global.d.ts

import { Connection } from 'mongoose'

declare global {
    var mongoose: any
}

export const mongoose = global.mongoose || new Connection()

if (process.env.NODE_ENV !== 'production') global.mongoose = mongoose

In tsconfig.json add to include:

...
"include": ["next-env.d.ts", "utils/global.d.ts", "**/*.ts", "**/*.tsx"],
...

The dbConnect.js:

import mongoose from 'mongoose'

const MONGODB_URI : string = process.env.MONGODB_URI || ''

if (!MONGODB_URI) {
    throw new Error(
        'Please define the MONGODB_URI environment variable inside .env.local'
    )
}

/**
 * Global is used here to maintain a cached connection across hot reloads
 * in development. This prevents connections growing exponentially
 * during API Route usage.
 */
let cached = global.mongoose

if (!cached) {
    cached = global.mongoose = { conn: null, promise: null }
}

async function dbConnect() {
    if (cached.conn) {
        return cached.conn
    }

    if (!cached.promise) {
        const opts = {
            bufferCommands: false,
        }


        cached.promise = mongoose.connect(MONGODB_URI, opts).then((mongoose) => {return mongoose});
    }
    cached.conn = await cached.promise
    return cached.conn
}

export default dbConnect

Untested

Upvotes: 0

Alisson Leal
Alisson Leal

Reputation: 194

Since you're technically extending the global context, you need to add its new types.

I usually have a custom.d.ts in the root folder for packages that don't have types.

In your case:

declare global {
  const mongoose: any
}

Also, don't forget to add custom.d.ts in tsconfig.json:

{
  "compilerOptions": {...},
  "include": ["...your other files", "custom.d.ts"],
}


reference with Prisma connection: https://stackoverflow.com/a/69434850/14122260

Upvotes: 2

Bryce Chan
Bryce Chan

Reputation: 1643

I don't see anything particularly wrong in your file, maybe check if your file is in the right directory, also your .env.local file.

This is the lib/dbConnect.js I used in my previous project just for your reference.

import mongoose from 'mongoose';

const MONGODB_URI = process.env.MONGODB_URI;

if (!MONGODB_URI) {
  throw new Error(
    'Please define the MONGODB_URI environment variable inside .env.local';
  )
}

let cached = global.mongoose;

if (!cached) {
  cached = global.mongoose = { conn: null, promise: null }
}

async function dbConnect () {
  if (cached.conn) {
    return cached.conn
  }

  if (!cached.promise) {
    const opts = {
      useNewUrlParser: true,
      useUnifiedTopology: true,
      bufferCommands: false,
      bufferMaxEntries: 0,
      useFindAndModify: true,
      useCreateIndex: true
    }

    cached.promise = mongoose.connect(MONGODB_URI, opts).then(mongoose => {
      return mongoose
    })
  }
  cached.conn = await cached.promise
  return cached.conn
}

export default dbConnect

Upvotes: 0

Related Questions