TypeScript: ¿Cómo definir el modelo en combinación con el uso de población de mangosta?

Resuelto maxpaj asked hace 6 años • 5 respuestas

Fondo

Estoy usando mangosta y TypeScript en mi aplicación Node.JS. Estoy usando mangosta populateen varios lugares cuando obtengo datos de la base de datos.

El problema al que me enfrento es que no sé cómo escribir mis modelos para que una propiedad pueda ser un ObjectId o completarse con datos de otra colección.

lo que he probado

Intenté usar tipos de unión en la definición de tipo de mi modelo, que parece algo que TypeScript ofrece para cubrir este tipo de cosas:

interface User extends Document {
    _id: Types.ObjectId;
    name: string
}

interface Item extends Document {
    _id: Types.ObjectId;

    // Union typing here
    user: Types.ObjectId | User;
}

Mi esquema solo define la propiedad como un ObjectId con ref.

const ItemSchema = new Schema({
    user: { type: Schema.Types.ObjectId, ref: "User", index: true }
})

Ejemplo :

Entonces podría hacer algo como esto:

ItemModel.findById(id).populate("user").then((item: Item) => {
    console.log(item.user.name);
})

Lo que produce el error de compilación:

[ts] Property 'name' does not exist on type 'User | ObjectId'.
     Property 'name' does not exist on type 'ObjectId'.

Pregunta

¿Cómo puedo tener una propiedad de modelo que pueda ser de dos tipos en TypeScript?

maxpaj avatar Dec 21 '17 17:12 maxpaj
Aceptado

Necesitas usar una protección tipográfica para limitar el tipo de letra Types.ObjectId | Usera User...

Si se trata de una Userclase, puede utilizar esto:

if (item.user instanceof User) {
    console.log(item.user.name);
} else {
    // Otherwise, it is a Types.ObjectId
}

Si tiene una estructura que coincide con una Userclase, pero no con una instancia (por ejemplo, si Useres una interfaz), necesitará una protección de tipo personalizada:

function isUser(obj: User | any) : obj is User {
    return (obj && obj.name && typeof obj.name === 'string');
}

Que puedes usar con:

if (isUser(item.user)) {
    console.log(item.user.name);
} else {
    // Otherwise, it is a Types.ObjectId
}

Si no desea verificar las estructuras para este propósito, puede utilizar una unión discriminada .

Fenton avatar Dec 21 '2017 10:12 Fenton

Transmita el item.userdestino a User, cuando el usuario esté completo.

ItemModel.findById(id).populate("user").then((item: Item) => {
    console.log((<User>item.user).name);
})
ruwan800 avatar Sep 26 '2019 05:09 ruwan800

Puedes usar PopulatedDocel tipo de la @types/mongooselib. Ver mangosta.doc .

Ahmed Bhouri avatar Jun 28 '2021 12:06 Ahmed Bhouri