Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Property 'updateDescription' does not exist on type 'Document<unknown, any #12942

Closed
1 task done
dong-lufei opened this issue Jan 25, 2023 · 5 comments · Fixed by #13696
Closed
1 task done

Property 'updateDescription' does not exist on type 'Document<unknown, any #12942

dong-lufei opened this issue Jan 25, 2023 · 5 comments · Fixed by #13696
Labels
docs This issue is due to a mistake or omission in the mongoosejs.com documentation typescript Types or Types-test related issue / Pull Request
Milestone

Comments

@dong-lufei
Copy link

Prerequisites

  • I have written a descriptive issue title

Mongoose version

6.8

Node.js version

18.13.0

MongoDB version

6.0.4

Operating system

Windows

Operating system version (i.e. 20.04, 11.3, 10)

10.0.22000

Issue

import { model, Schema } from "npm:mongoose@^6.8";

// Define schema.
const dinosaurSchema = new Schema({
  name: { type: String, unique: true },
  description: String,
  createdAt: { type: Date, default: Date.now },
  updatedAt: { type: Date, default: Date.now },
});

// Validations
dinosaurSchema.path("name").required(true, "Dinosaur name cannot be blank.");
dinosaurSchema.path("description").required(
  true,
  "Dinosaur description cannot be blank.",
);

// Methods.
dinosaurSchema.methods = {
  // Update description.
  updateDescription: async function (description: string) {
    this.description = description;
    return await this.save();
  },
};

// Export model.
export default model("Dinosaur", dinosaurSchema);

import mongoose from "npm:mongoose@^6.8";
import Dinosaur from "./model/Dinosaur.ts";

await mongoose.connect("mongodb://localhost:27017");

// Check to see connection status.
console.log(mongoose.connection.readyState);

// Create a new Dinosaur.
const deno = new Dinosaur({
  name: "Deno",
  description: "The fastest dinosaur ever lived.",
});

// // Insert deno.
await deno.save();

// Find Deno by name.
const denoFromMongoDb = await Dinosaur.findOne({ name: "Deno" });
console.log(
  `Finding Deno in MongoDB -- \n  ${denoFromMongoDb?.name}: ${denoFromMongoDb?.description}`,
);

// Update description for Deno and save it.
await denoFromMongoDb?.updateDescription(
  "The fastest and most secure dinosaur ever lived.",
);

The last method above updateDescription code hints that the type is wrong:

Property 'updateDescription' does not exist on type 'Document<unknown, any, { createdAt: Date; updatedAt: Date; description?: string | undefined; name?: string | undefined; }> & { createdAt: Date; updatedAt: Date; description?: string | undefined; name?: string | undefined; } & { ...; }'.deno-ts(2339)

@dong-lufei dong-lufei added help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary help wanted labels Jan 25, 2023
@IslandRhythms IslandRhythms added typescript Types or Types-test related issue / Pull Request and removed help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary help wanted labels Jan 25, 2023
@IslandRhythms
Copy link
Collaborator

Am able to reproduce

@vkarpov15 vkarpov15 added this to the TypeScript backlog milestone Feb 6, 2023
@r3wt
Copy link

r3wt commented Jul 8, 2023

nasty but works:

type T1=any;
type AccountMethods = { checkPassword: (candidatePassword: string)=>Promise<boolean>; };
const AccountSchema = new Schema<T1,Model<T1, any, AccountMethods, any>,AccountMethods>({});

@vkarpov15
Copy link
Collaborator

Does this issue just show up in VS Code highlighting, or is there an actual failure when you run tsc?

@IslandRhythms
Copy link
Collaborator

@vkarpov15 failure when running tsc

import * as mongoose from "mongoose";

// Define schema.
const dinosaurSchema = new mongoose.Schema({
  name: { type: String, unique: true },
  description: String,
  createdAt: { type: Date, default: Date.now },
  updatedAt: { type: Date, default: Date.now },
});

// Validations
dinosaurSchema.path("name").required(true, "Dinosaur name cannot be blank.");
dinosaurSchema.path("description").required(
  true,
  "Dinosaur description cannot be blank.",
);

// Methods.
dinosaurSchema.methods = {
  // Update description.
  updateDescription: async function (description: string) {
    this.description = description;
    return await this.save();
  },
};

const Dinosaur = mongoose.model('Dinosaur', dinosaurSchema);

async function run() {
  await mongoose.connect('mongodb://localhost:27017');
  await mongoose.connection.dropDatabase();

  // Check to see connection status.
console.log(mongoose.connection.readyState);

// Create a new Dinosaur.
const deno = new Dinosaur({
  name: "Deno",
  description: "The fastest dinosaur ever lived.",
});

// // Insert deno.
await deno.save();

// Find Deno by name.
const denoFromMongoDb = await Dinosaur.findOne({ name: "Deno" });
console.log(
  `Finding Deno in MongoDB -- \n  ${denoFromMongoDb?.name}: ${denoFromMongoDb?.description}`,
);

// Update description for Deno and save it.
await denoFromMongoDb?.updateDescription(
  "The fastest and most secure dinosaur ever lived.",
);
}

run();

image

@vkarpov15 vkarpov15 added the docs This issue is due to a mistake or omission in the mongoosejs.com documentation label Aug 2, 2023
@vkarpov15
Copy link
Collaborator

If you don't want to mess with generics, the preferred approach is to define your methods directly in your call to the Mongoose Schema() constructor using the methods option as follows. This allows Mongoose's automatic type inference to pick up your methods:

// Define schema.
const dinosaurSchema = new mongoose.Schema({
  name: { type: String, unique: true },
  description: String,
  createdAt: { type: Date, default: Date.now },
  updatedAt: { type: Date, default: Date.now },
}, {
  methods: {
    updateDescription: async function (description: string) {
      this.description = description;
      return await this.save();
    }
  }
});

If you can't use that approach, you can pass generics to your Schema constructor as follows:

interface DinosaurType {
  name?: string;
  description?: string;
  createdAt: Date;
  updatedAt: Date;
}

// Define schema.
const dinosaurSchema = new mongoose.Schema<DinosaurType, mongoose.Model<DinosaurType>, { updateDescription: Function }>({
  name: { type: String, unique: true },
  description: String,
  createdAt: { type: Date, default: Date.now },
  updatedAt: { type: Date, default: Date.now },
});

We'll add some notes to the Mongoose docs about this.

vkarpov15 added a commit that referenced this issue Aug 2, 2023
…cs, add info on using methods with generics

Fix #12942
vkarpov15 added a commit that referenced this issue Aug 3, 2023
docs(typescript): highlight auto type inference for methods and statics, add info on using methods with generics
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs This issue is due to a mistake or omission in the mongoosejs.com documentation typescript Types or Types-test related issue / Pull Request
Projects
None yet
4 participants