node.js - Kan inte använda generisk modell i mongoose: Argument av typen 'x' kan inte tilldelas till parametern av typen MongooseFilterQuery


Jag försöker skicka en generell Mongoose-modell som en parameter till en funktion.

import mongoose, { Document, Model, Schema } from 'mongoose';

interface User {
    name: string;
    age: number;
    favouriteAnimal: string;
}

const UserSchema = new Schema({
    name: String,
    age: Number,
    favouriteAnimal: String,
});

const UserModel = mongoose.model<User & Document>('User', UserSchema);

function doSomething() {
    return UserModel.findOne({ user: 'john' }); // This is fine.
}

async function doSomethingGeneric<T extends User & Document>(model: Model<T>, key: keyof T) {
    const user = await model.findOne({ user: 'john' }); // Compiler errors on this line.
    return user![key];
}

Detta är felutdata från kompilatorn:

error TS2345: Argument of type '{ user: string; }' is not assignable to parameter of type 'MongooseFilterQuery<Pick<T, Exclude<keyof T, "toString" | "removeListener" | "off" | "update" | "invalidate" | "increment" | "model" | "$isDeleted" | "remove" | "save" | "__v" | "$isDefault" | "$session" | ... 47 more ... | "modelName">>>'.

Type '{ user: string; }' is not assignable to type '{ [P in keyof Pick<T, Exclude<keyof T, "toString" | "removeListener" | "off" | "update" | "invalidate" | "increment" | "model" | "$isDeleted" | "remove" | "save" | "__v" | "$isDefault" | "$session" | ... 47 more ... | "modelName">>]?: (P extends "_id" ? [...] extends [...] ? Condition<...> : Condition<...> : [...] e...'.

23    const user = await model.findOne({ user: 'john' });

Typen av UserModel är mongoose.Model<User & mongoose.Document, {}>, så jag skulle ha förväntat mig att den generiska uppfyller samma typbegränsningar som den icke-generiska metoden. Var har jag fel?

Redigera: Jag har återskapat problemet i TS-lekplatsen så att du kan se det direkt.

Svar #1

Detta har bekräftats vara en Typescript-bugg: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/39358

En möjlig lösning är att manuellt kasta frågeobjektet till rätt typ:

async function doSomethingGeneric<T extends User & Document>(model: Model<T>, key: keyof T) {
    const user = await model.findOne({ user: 'john' } as FilterQuery<T>);
    return user![key];                    /* add this ^^^^^^^^^^^^^^^^^ */
}

Relaterade artiklar