diff --git a/index.d.ts b/index.d.ts index f7e55c951c..01cb6ac41c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1064,6 +1064,8 @@ declare module 'mongoose' { type SchemaPreOptions = { document?: boolean, query?: boolean }; type SchemaPostOptions = { document?: boolean, query?: boolean }; + type ExtractQueryHelpers = M extends Model ? TQueryHelpers : {}; + class Schema = Model, SchemaDefinitionType = undefined> extends events.EventEmitter { /** * Create a new schema @@ -1167,7 +1169,7 @@ declare module 'mongoose' { pre = M>(method: 'insertMany' | RegExp, options: SchemaPreOptions, fn: (this: T, next: (err: CallbackError) => void) => void): this; /** Object of currently defined query helpers on this schema. */ - query: { [name: string]: = Query>(this: T, ...args: any[]) => any }; + query: { [name: string]: > = QueryWithHelpers>>(this: T, ...args: any[]) => any }; /** Adds a method call to the queue. */ queue(name: string, args: any[]): this; @@ -1852,7 +1854,7 @@ declare module 'mongoose' { exec(callback?: (err: any, result: ResultType) => void): Promise | any; // eslint-disable-next-line @typescript-eslint/ban-types - $where(argument: string | Function): Query; + $where(argument: string | Function): QueryWithHelpers; /** Specifies an `$all` query condition. When called with one argument, the most recent path passed to `where()` is used. */ all(val: Array): this; @@ -1888,12 +1890,12 @@ declare module 'mongoose' { comment(val: string): this; /** Specifies this query as a `count` query. */ - count(callback?: (err: any, count: number) => void): Query; - count(criteria: FilterQuery, callback?: (err: any, count: number) => void): Query; + count(callback?: (err: any, count: number) => void): QueryWithHelpers; + count(criteria: FilterQuery, callback?: (err: any, count: number) => void): QueryWithHelpers; /** Specifies this query as a `countDocuments` query. */ - countDocuments(callback?: (err: any, count: number) => void): Query; - countDocuments(criteria: FilterQuery, callback?: (err: any, count: number) => void): Query; + countDocuments(callback?: (err: any, count: number) => void): QueryWithHelpers; + countDocuments(criteria: FilterQuery, callback?: (err: any, count: number) => void): QueryWithHelpers; /** * Returns a wrapper around a [mongodb driver cursor](http://mongodb.github.io/node-mongodb-native/2.1/api/Cursor.html). @@ -1906,17 +1908,17 @@ declare module 'mongoose' { * remove, except it deletes _every_ document that matches `filter` in the * collection, regardless of the value of `single`. */ - deleteMany(filter?: FilterQuery, options?: QueryOptions, callback?: (err: CallbackError, res: any) => void): Query; + deleteMany(filter?: FilterQuery, options?: QueryOptions, callback?: (err: CallbackError, res: any) => void): QueryWithHelpers; /** * Declare and/or execute this query as a `deleteOne()` operation. Works like * remove, except it deletes at most one document regardless of the `single` * option. */ - deleteOne(filter?: FilterQuery, options?: QueryOptions, callback?: (err: CallbackError, res: any) => void): Query; + deleteOne(filter?: FilterQuery, options?: QueryOptions, callback?: (err: CallbackError, res: any) => void): QueryWithHelpers; /** Creates a `distinct` query: returns the distinct values of the given `field` that match `filter`. */ - distinct(field: string, filter?: FilterQuery, callback?: (err: any, count: number) => void): Query, DocType, THelpers>; + distinct(field: string, filter?: FilterQuery, callback?: (err: any, count: number) => void): QueryWithHelpers, DocType, THelpers>; /** Specifies a `$elemMatch` query condition. When called with one argument, the most recent path passed to `where()` is used. */ // eslint-disable-next-line @typescript-eslint/ban-types @@ -1935,7 +1937,7 @@ declare module 'mongoose' { equals(val: any): this; /** Creates a `estimatedDocumentCount` query: counts the number of documents in the collection. */ - estimatedDocumentCount(options?: QueryOptions, callback?: (err: any, count: number) => void): Query; + estimatedDocumentCount(options?: QueryOptions, callback?: (err: any, count: number) => void): QueryWithHelpers; /** Specifies a `$exists` query condition. When called with one argument, the most recent path passed to `where()` is used. */ exists(val: boolean): this; @@ -1950,31 +1952,31 @@ declare module 'mongoose' { explain(verbose?: string): this; /** Creates a `find` query: gets a list of documents that match `filter`. */ - find(callback?: (err: any, docs: DocType[]) => void): Query, DocType, THelpers>; - find(filter: FilterQuery, callback?: (err: any, docs: DocType[]) => void): Query, DocType, THelpers>; - find(filter: FilterQuery, projection?: any | null, options?: QueryOptions | null, callback?: (err: CallbackError, docs: DocType[]) => void): Query, DocType, THelpers>; + find(callback?: (err: any, docs: DocType[]) => void): QueryWithHelpers, DocType, THelpers>; + find(filter: FilterQuery, callback?: (err: any, docs: DocType[]) => void): QueryWithHelpers, DocType, THelpers>; + find(filter: FilterQuery, projection?: any | null, options?: QueryOptions | null, callback?: (err: CallbackError, docs: DocType[]) => void): QueryWithHelpers, DocType, THelpers>; /** Declares the query a findOne operation. When executed, the first found document is passed to the callback. */ - findOne(filter?: FilterQuery, projection?: any | null, options?: QueryOptions | null, callback?: (err: CallbackError, doc: DocType | null) => void): Query; + findOne(filter?: FilterQuery, projection?: any | null, options?: QueryOptions | null, callback?: (err: CallbackError, doc: DocType | null) => void): QueryWithHelpers; /** Creates a `findOneAndDelete` query: atomically finds the given document, deletes it, and returns the document as it was before deletion. */ - findOneAndDelete(filter?: FilterQuery, options?: QueryOptions | null, callback?: (err: any, doc: DocType | null, res: any) => void): Query; + findOneAndDelete(filter?: FilterQuery, options?: QueryOptions | null, callback?: (err: any, doc: DocType | null, res: any) => void): QueryWithHelpers; /** Creates a `findOneAndRemove` query: atomically finds the given document and deletes it. */ - findOneAndRemove(filter?: FilterQuery, options?: QueryOptions | null, callback?: (err: any, doc: DocType | null, res: any) => void): Query; + findOneAndRemove(filter?: FilterQuery, options?: QueryOptions | null, callback?: (err: any, doc: DocType | null, res: any) => void): QueryWithHelpers; /** Creates a `findOneAndUpdate` query: atomically find the first document that matches `filter` and apply `update`. */ - findOneAndUpdate(filter: FilterQuery, update: UpdateQuery, options: QueryOptions & { rawResult: true }, callback?: (err: any, doc: mongodb.FindAndModifyWriteOpResultObject, res: any) => void): Query, DocType, THelpers>; - findOneAndUpdate(filter: FilterQuery, update: UpdateQuery, options: QueryOptions & { upsert: true } & ReturnsNewDoc, callback?: (err: any, doc: DocType, res: any) => void): Query; - findOneAndUpdate(filter?: FilterQuery, update?: UpdateQuery, options?: QueryOptions | null, callback?: (err: any, doc: DocType | null, res: any) => void): Query; + findOneAndUpdate(filter: FilterQuery, update: UpdateQuery, options: QueryOptions & { rawResult: true }, callback?: (err: any, doc: mongodb.FindAndModifyWriteOpResultObject, res: any) => void): QueryWithHelpers, DocType, THelpers>; + findOneAndUpdate(filter: FilterQuery, update: UpdateQuery, options: QueryOptions & { upsert: true } & ReturnsNewDoc, callback?: (err: any, doc: DocType, res: any) => void): QueryWithHelpers; + findOneAndUpdate(filter?: FilterQuery, update?: UpdateQuery, options?: QueryOptions | null, callback?: (err: any, doc: DocType | null, res: any) => void): QueryWithHelpers; /** Creates a `findByIdAndDelete` query, filtering by the given `_id`. */ - findByIdAndDelete(id?: mongodb.ObjectId | any, options?: QueryOptions | null, callback?: (err: any, doc: DocType | null, res: any) => void): Query; + findByIdAndDelete(id?: mongodb.ObjectId | any, options?: QueryOptions | null, callback?: (err: any, doc: DocType | null, res: any) => void): QueryWithHelpers; /** Creates a `findOneAndUpdate` query, filtering by the given `_id`. */ - findByIdAndUpdate(id: mongodb.ObjectId | any, update: UpdateQuery, options: QueryOptions & { rawResult: true }, callback?: (err: any, doc: mongodb.FindAndModifyWriteOpResultObject, res: any) => void): Query, DocType, THelpers>; - findByIdAndUpdate(id: mongodb.ObjectId | any, update: UpdateQuery, options: QueryOptions & { upsert: true } & ReturnsNewDoc, callback?: (err: any, doc: DocType, res: any) => void): Query; - findByIdAndUpdate(id?: mongodb.ObjectId | any, update?: UpdateQuery, options?: QueryOptions | null, callback?: (err: any, doc: DocType | null, res: any) => void): Query; + findByIdAndUpdate(id: mongodb.ObjectId | any, update: UpdateQuery, options: QueryOptions & { rawResult: true }, callback?: (err: any, doc: mongodb.FindAndModifyWriteOpResultObject, res: any) => void): QueryWithHelpers, DocType, THelpers>; + findByIdAndUpdate(id: mongodb.ObjectId | any, update: UpdateQuery, options: QueryOptions & { upsert: true } & ReturnsNewDoc, callback?: (err: any, doc: DocType, res: any) => void): QueryWithHelpers; + findByIdAndUpdate(id?: mongodb.ObjectId | any, update?: UpdateQuery, options?: QueryOptions | null, callback?: (err: any, doc: DocType | null, res: any) => void): QueryWithHelpers; /** Specifies a `$geometry` condition */ geometry(object: { type: string, coordinates: any[] }): this; @@ -2023,7 +2025,7 @@ declare module 'mongoose' { j(val: boolean | null): this; /** Sets the lean option. */ - lean>(val?: boolean | any): Query; + lean>(val?: boolean | any): QueryWithHelpers; /** Specifies the maximum number of documents the query will return. */ limit(val: number): this; @@ -2040,7 +2042,7 @@ declare module 'mongoose' { * Runs a function `fn` and treats the return value of `fn` as the new value * for the query to resolve to. */ - map(fn: (doc: DocType) => MappedType): Query; + map(fn: (doc: DocType) => MappedType): QueryWithHelpers; /** Specifies an `$maxDistance` query condition. When called with one argument, the most recent path passed to `where()` is used. */ maxDistance(val: number): this; @@ -2092,7 +2094,7 @@ declare module 'mongoose' { * This is handy for integrating with async/await, because `orFail()` saves you * an extra `if` statement to check if no document was found. */ - orFail(err?: NativeError | (() => NativeError)): Query, DocType, THelpers>; + orFail(err?: NativeError | (() => NativeError)): QueryWithHelpers, DocType, THelpers>; /** Specifies a `$polygon` condition */ polygon(...coordinatePairs: number[][]): this; @@ -2120,14 +2122,14 @@ declare module 'mongoose' { * deprecated, you should use [`deleteOne()`](#query_Query-deleteOne) * or [`deleteMany()`](#query_Query-deleteMany) instead. */ - remove(filter?: FilterQuery, callback?: (err: CallbackError, res: mongodb.WriteOpResult['result']) => void): Query; + remove(filter?: FilterQuery, callback?: (err: CallbackError, res: mongodb.WriteOpResult['result']) => void): QueryWithHelpers; /** * Declare and/or execute this query as a replaceOne() operation. Same as * `update()`, except MongoDB will replace the existing document and will * not accept any [atomic](https://docs.mongodb.com/manual/tutorial/model-data-for-atomic-operations/#pattern) operators (`$set`, etc.) */ - replaceOne(filter?: FilterQuery, replacement?: DocumentDefinition, options?: QueryOptions | null, callback?: (err: any, res: any) => void): Query; + replaceOne(filter?: FilterQuery, replacement?: DocumentDefinition, options?: QueryOptions | null, callback?: (err: any, res: any) => void): QueryWithHelpers; /** Specifies which document fields to include or exclude (also known as the query "projection") */ select(arg: string | any): this; @@ -2193,10 +2195,10 @@ declare module 'mongoose' { then: Promise['then']; /** Converts this query to a customized, reusable query constructor with all arguments and options retained. */ - toConstructor(): new (...args: any[]) => Query; + toConstructor(): new (...args: any[]) => QueryWithHelpers; /** Declare and/or execute this query as an update() operation. */ - update(filter?: FilterQuery, update?: UpdateQuery, options?: QueryOptions | null, callback?: (err: CallbackError, res: UpdateWriteOpResult) => void): Query; + update(filter?: FilterQuery, update?: UpdateQuery, options?: QueryOptions | null, callback?: (err: CallbackError, res: UpdateWriteOpResult) => void): QueryWithHelpers; /** * Declare and/or execute this query as an updateMany() operation. Same as @@ -2204,13 +2206,13 @@ declare module 'mongoose' { * `filter` (as opposed to just the first one) regardless of the value of * the `multi` option. */ - updateMany(filter?: FilterQuery, update?: UpdateQuery, options?: QueryOptions | null, callback?: (err: CallbackError, res: UpdateWriteOpResult) => void): Query; + updateMany(filter?: FilterQuery, update?: UpdateQuery, options?: QueryOptions | null, callback?: (err: CallbackError, res: UpdateWriteOpResult) => void): QueryWithHelpers; /** * Declare and/or execute this query as an updateOne() operation. Same as * `update()`, except it does not support the `multi` or `overwrite` options. */ - updateOne(filter?: FilterQuery, update?: UpdateQuery, options?: QueryOptions | null, callback?: (err: CallbackError, res: UpdateWriteOpResult) => void): Query; + updateOne(filter?: FilterQuery, update?: UpdateQuery, options?: QueryOptions | null, callback?: (err: CallbackError, res: UpdateWriteOpResult) => void): QueryWithHelpers; /** * Sets the specified number of `mongod` servers, or tag set of `mongod` servers, diff --git a/test/typescript/queries.ts b/test/typescript/queries.ts index 2642736176..f41cb35b1f 100644 --- a/test/typescript/queries.ts +++ b/test/typescript/queries.ts @@ -1,16 +1,16 @@ -import { Schema, model, Document, Types, Query, Model } from 'mongoose'; +import { Schema, model, Document, Types, Query, Model, QueryWithHelpers } from 'mongoose'; interface QueryHelpers { - byName(name: string): Query, ITest, QueryHelpers>; + byName(name: string): QueryWithHelpers, ITest, QueryHelpers>; } -const schema: Schema> = new Schema({ +const schema: Schema> = new Schema({ name: { type: 'String' }, tags: [String], docs: [{ nested: { id: Number } }] }); -schema.query.byName = function(name: string): Query, ITest, QueryHelpers> { +schema.query.byName = function(name: string): Query & QueryHelpers { return this.find({ name }); }; @@ -28,7 +28,7 @@ interface ITest extends Document { const Test = model>('Test', schema); -Test.find().byName('test').orFail().exec().then(console.log); +Test.find().byName('test').byName('test2').orFail().exec().then(console.log); Test.count({ name: /Test/ }).exec().then((res: number) => console.log(res)); Test.findOne({ 'docs.id': 42 }).exec().then(console.log);