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

TypeScript: Document type not passed along with collection() #11131

Closed
SteffenLanger opened this issue Dec 22, 2021 · 4 comments
Closed

TypeScript: Document type not passed along with collection() #11131

SteffenLanger opened this issue Dec 22, 2021 · 4 comments
Labels
typescript Types or Types-test related issue / Pull Request
Milestone

Comments

@SteffenLanger
Copy link

SteffenLanger commented Dec 22, 2021

Do you want to request a feature or report a bug?
Bug 🐞

What is the current behavior?
This is a type definition issue.

Let's assume the documents in a collection have an _id of type string. When updating a document in that collection using a query for _id, TypeScript shows the error "TS2322: Type 'string' is not assignable to type 'Condition'."

If the current behavior is a bug, please provide the steps to reproduce.
Write this code:

import mongoose from 'mongoose';

await mongoose.connection.collection('teams').updateOne({_id : 'abc-ID'}, {
    $set : {
        'name' : 'New team name'
    }
});

Currently, MongoDB's types have a Document parameter while Mongoose's types do not:
MongoDB type (extracts)

export declare class Collection<TSchema extends Document = Document> {

updateOne(filter: Filter<TSchema>, update: UpdateFilter<TSchema> | Partial<TSchema>): Promise<UpdateResult>;

Mongoose type (extract)

interface Collection extends CollectionBase {

interface CollectionBase extends mongodb.Collection {

Mongoose uses MongoDB's type definition for updateOne. Since no parameter is passed to the Collection above, the default type "Document" is assumed and that requires an ObjectID.

My tsconfig.json:

{
    "compilerOptions": {
        "module": "ES2020",
        "esModuleInterop": true,
        "target": "ES2021",
        "noImplicitAny": false,
        "moduleResolution": "node",
        "sourceMap": true,
        "resolveJsonModule": true,
        "lib": [
            "dom",
            "ES2021"
        ]
    }
}

What is the expected behavior?
The type of the function mongoose.connection.collection should have a parameter Document that is passed to the underlying MongoDB type Collection. Example:

interface Collection<TSchema extends Document = Document> extends CollectionBase<TSchema> {

interface CollectionBase<TSchema extends Document = Document> extends mongodb.Collection<TSchema> {

Then, the _id would be recognized as a string from the Document definition type parameter TSchema. No error would be shown.

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.
Node.js: v16.13.1
Mongoose: 6.1.2
MongoDB: 4.4.10

@DavideViolante
Copy link
Contributor

DavideViolante commented Dec 22, 2021

Not happening to me with the following code and same version.

...
const MyModel = model<IMyModel>('MyModel', myModelSchema);

await MyModel.updateOne({ _id: 'abc-ID'}, {
  $set: { name: 'New team name' }
});

Btw try to update to 6.1.3 or change your code to something like this:

await Teams.updateOne({ _id: 'abc-ID' }, { 'name': 'New team name' });
// where Teams is the model as MyModel above

more info https://mongoosejs.com/docs/typescript/schemas.html

@IslandRhythms IslandRhythms added the help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary label Dec 22, 2021
@SteffenLanger
Copy link
Author

True, but that solution completely avoids the wrongly defined types on the connection 😁 Another workaround would be this code (note the .db after connection which accesses the MongoDB connection object with a collection function that can be typed):

import mongoose from 'mongoose';
interface Team {
  _id: string;
  name: string;
}

await mongoose.connection.db.collection<Team>('teams').updateOne({_id : 'abc-ID'}, {
    $set : {
        'name' : 'New team name'
    }
});

This GitHub issue is not meant to get a working solution - I got that. It's a contribution to help fix the types.

The use case for the code posted above is data migrations. Models might have been updated to have default values or field validations that should not be used within the migration.

@DavideViolante
Copy link
Contributor

DavideViolante commented Dec 23, 2021

I can reproduce with v6.1.3 and the error showed is:

(property) _id?: Condition<ObjectId>
Type 'string' is not assignable to type 'Condition<ObjectId>'.ts(2322)
mongodb.d.ts(5858, 5): The expected type comes from property '_id' which is declared here on type 'Filter<Document>'

it seems like the error is coming from mongodb, not mongoose types, if I'm not mistaken?

@vkarpov15 vkarpov15 added this to the 6.1.7 milestone Dec 27, 2021
@SteffenLanger
Copy link
Author

Yes, the error is caused by the MongoDB types - and it should be that way. The underlying issue lies within the Mongoose types, however. Mongoose uses MongoDB's types for updateOne() and other operations. MongoDB's types would work correctly if Mongoose passed its collection type to MongoDB's collection type.

@vkarpov15 vkarpov15 modified the milestones: 6.1.7, 6.1.8 Jan 8, 2022
@vkarpov15 vkarpov15 modified the milestones: 6.1.8, 6.1.9, 6.1.10 Jan 24, 2022
@vkarpov15 vkarpov15 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 labels Feb 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
typescript Types or Types-test related issue / Pull Request
Projects
None yet
Development

No branches or pull requests

4 participants