简体   繁体   中英

How to extend Mongoose Schema in Typescript

I'm making 3 schemas ( article , comment , user ) and models that share some fields.

FYI, I'm working with mongoose and typescript.

  • mongoose v6.1.4
  • nodejs v16.13.1
  • typescript v4.4.3

interface of each 3 schema shares a common interface UserContent , and they looks like this:

interface IUserContent {
  slug: string;
  should_show: 'always' | 'never' | 'by_date';
  show_date_from: Date | null;
  show_date_to: Date | null;
  published_date: Date | null;
}

interface IArticle extends IUserContent {
  title: string;
  content: string;
  user_id: number;
}

interface IComment extends IUserContent {
  content: string;
  user_id: number;
}

interface IUser extends IUserContent {
  name: string;
  description: string;
}

And I'm trying to make an function which creates Mongoose Schema with shared fields:

import { Schema, SchemaDefinition } from 'mongoose'

const createUserContentSchema = <T extends object>(fields: SchemaDefinition<T>) => {
  const schema = new Schema<IUserContent & T>({
    // theese fields are shared fields
    slug: { type: String },
    should_show: { type: String, enum: ['always', 'never', 'by_date'] },
    show_date_from: { type: Date },
    show_date_to: { type: Date },
    published_date: { type: Date },

    // this is not-shared fields
    ...fields,
  })
  return schema
}

I was expected that this function will create schema with shared fields and non-shared fields combined together. (like code below)

const UserSchema = createUserContentSchema<IUser>({
  name: {type: String},
  description: {type: String},
});

However, It throws Type Error on the object parameter in new Schema which is inside createUserContentSchema function. (nevertheless compiled javascript code works well as expected)

Type '{ slug: { type: StringConstructor; }; should_show: { type: StringConstructor; enum: string[]; }; show_date_from: { type: DateConstructor; }; show_date_to: {...; }; published_date: {...; }; } & SchemaDefinition' is not assignable to type 'SchemaDefinition<SchemaDefinitionType<IUserContent & T>>'.ts(2345)

I removed generic from createUserContentSchema function and directly replaced T to IUser and it turns out to be nice without error. So, I'm assuring that I made mistake in typing generic. but can't figure out what did I make wrong exactly.

I want to fix my code to not make this Type Error.

PS

I found out that my error is reproduced only in mongoose@v6 (not v5) I read the breaking changes in update note but can't figure why this error is being produced in v6.

Mongoose Discriminator sounds like a feature you need.

https://mongoosejs.com/docs/api.html#model_Model.discriminator

function BaseSchema() {
  Schema.apply(this, arguments);

  this.add({
    name: String,
    createdAt: Date
  });
}
util.inherits(BaseSchema, Schema);

const PersonSchema = new BaseSchema();
const BossSchema = new BaseSchema({ department: String });

const Person = mongoose.model('Person', PersonSchema);
const Boss = Person.discriminator('Boss', BossSchema);
new Boss().__t; // "Boss". `__t` is the default `discriminatorKey`

const employeeSchema = new Schema({ boss: ObjectId });
const Employee = Person.discriminator('Employee', employeeSchema, 'staff');
new Employee().__t; // "staff" because of 3rd argument above

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM