diff --git a/benchmarks/typescript/simple/package.json b/benchmarks/typescript/simple/package.json index 6571d866d06..b936a44a756 100644 --- a/benchmarks/typescript/simple/package.json +++ b/benchmarks/typescript/simple/package.json @@ -1,7 +1,7 @@ { "dependencies": { "mongoose": "file:../../../mongoose.tgz", - "typescript": "5.5.x" + "typescript": "5.8.x" }, "scripts": { "benchmark": "tsc --extendedDiagnostics" diff --git a/test/types/discriminator.test.ts b/test/types/discriminator.test.ts index fa8e9a3a1b0..87b36d94944 100644 --- a/test/types/discriminator.test.ts +++ b/test/types/discriminator.test.ts @@ -1,4 +1,5 @@ import mongoose, { Document, Model, Schema, SchemaDefinition, SchemaOptions, Types, model } from 'mongoose'; +import { expectType } from 'tsd'; const schema: Schema = new Schema({ name: { type: 'String' } }); @@ -76,3 +77,42 @@ function test(): void { const sampleCardDb: CardDb = sampleLandDb; } + +function gh15535() { + const ParentSchema = new Schema({ + field1: { + type: String, + required: true + }, + field2: Number + }, { + discriminatorKey: 'field1', + methods: { + getField2() { + return this.field2; + } + } + }); + + const ParentModel = mongoose.model('Parent', ParentSchema); + + const ChildSchema = new Schema({ + field3: String + }, { + methods: { + getField3() { + return this.field3; + } + } + }); + + + const ChildModel = ParentModel.discriminator('child', ChildSchema); + + const doc = new ChildModel({}); + expectType(doc.field1); + expectType(doc.field2); + expectType(doc.getField2()); + expectType(doc.field3); + expectType(doc.getField3()); +} diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index a19a910612b..e798d4bb50a 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -532,7 +532,7 @@ export function autoTypedSchema() { }, { statics: { staticFn() { - expectType>>(this); + expectAssignable>>(this); return 'Returned from staticFn' as const; } }, diff --git a/types/index.d.ts b/types/index.d.ts index effc39c8203..a6a1bb71ac0 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -607,7 +607,7 @@ declare module 'mongoose' { | typeof Schema.Types.UUID; - export type InferId = T extends { _id?: any } ? T['_id'] : Types.ObjectId; + export type InferId = mongodb.InferIdType; export interface VirtualTypeOptions { /** If `ref` is not nullish, this becomes a populated virtual. */ @@ -902,11 +902,6 @@ declare module 'mongoose' { export type SchemaDefinitionType = T extends Document ? Omit> : T; - /** - * Helper to choose the best option between two type helpers - */ - export type _pickObject = T1 extends false ? T2 extends false ? Fallback : T2 : T1; - /* for ts-mongoose */ export class mquery { } diff --git a/types/models.d.ts b/types/models.d.ts index 8b98d38563e..6dbc8952eef 100644 --- a/types/models.d.ts +++ b/types/models.d.ts @@ -273,7 +273,6 @@ declare module 'mongoose' { THydratedDocumentType = HydratedDocument, TSchema = any> extends NodeJS.EventEmitter, - AcceptsDiscriminator, IndexManager, SessionStarter { new >(doc?: DocType, fields?: any | null, options?: boolean | AnyObject): THydratedDocumentType; @@ -313,11 +312,11 @@ declare module 'mongoose' { * round trip to the MongoDB server. */ bulkWrite( - writes: Array>, + writes: Array>, options: MongooseBulkWriteOptions & { ordered: false } ): Promise; bulkWrite( - writes: Array>, + writes: Array>, options?: MongooseBulkWriteOptions ): Promise; @@ -426,6 +425,28 @@ declare module 'mongoose' { TInstanceMethods & TVirtuals >; + /** Adds a discriminator type. */ + discriminator>( + name: string | number, + schema: TDiscriminatorSchema, + value?: string | number | ObjectId | DiscriminatorOptions + ): Model< + TRawDocType & InferSchemaType, + TQueryHelpers & ObtainSchemaGeneric, + TInstanceMethods & ObtainSchemaGeneric, + TVirtuals & ObtainSchemaGeneric + > & ObtainSchemaGeneric; + discriminator( + name: string | number, + schema: Schema, + value?: string | number | ObjectId | DiscriminatorOptions + ): Model; + discriminator( + name: string | number, + schema: Schema, + value?: string | number | ObjectId | DiscriminatorOptions + ): U; + /** * Delete an existing [Atlas search index](https://www.mongodb.com/docs/atlas/atlas-search/create-index/) by name. * This function only works when connected to MongoDB Atlas. @@ -885,7 +906,7 @@ declare module 'mongoose' { replaceOne( filter?: RootFilterQuery, replacement?: TRawDocType | AnyObject, - options?: (mongodb.ReplaceOptions & MongooseQueryOptions) | null + options?: (mongodb.ReplaceOptions & QueryOptions) | null ): QueryWithHelpers; /** Apply changes made to this model's schema after this model was compiled. */ diff --git a/types/query.d.ts b/types/query.d.ts index e625ec56635..5bfcd63fdcf 100644 --- a/types/query.d.ts +++ b/types/query.d.ts @@ -31,19 +31,9 @@ declare module 'mongoose' { | 'strictQuery' | 'translateAliases'; - type MongooseQueryOptions< - DocType = unknown, - Keys extends keyof QueryOptions = MongooseBaseQueryOptionKeys | 'timestamps' | 'lean' - > = Pick, Keys> & { - [other: string]: any; - }; + type MongooseBaseQueryOptions = Pick, MongooseBaseQueryOptionKeys>; - type MongooseBaseQueryOptions = MongooseQueryOptions; - - type MongooseUpdateQueryOptions = MongooseQueryOptions< - DocType, - MongooseBaseQueryOptionKeys | 'timestamps' - >; + type MongooseUpdateQueryOptions = Pick, MongooseBaseQueryOptionKeys | 'timestamps'>; type ProjectionFields = { [Key in keyof DocType]?: any } & Record; @@ -239,7 +229,7 @@ declare module 'mongoose' { : MergeType; class Query> implements SessionOperation { - _mongooseOptions: MongooseQueryOptions; + _mongooseOptions: QueryOptions; /** * Returns a wrapper around a [mongodb driver cursor](https://mongodb.github.io/node-mongodb-native/4.9/classes/FindCursor.html). @@ -634,7 +624,7 @@ declare module 'mongoose' { * Getter/setter around the current mongoose-specific options for this query * Below are the current Mongoose-specific options. */ - mongooseOptions(val?: MongooseQueryOptions): MongooseQueryOptions; + mongooseOptions(val?: QueryOptions): QueryOptions; /** Specifies a `$ne` query condition. When called with one argument, the most recent path passed to `where()` is used. */ ne(path: K, val: any): this;