Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Revert "types: make init hooks types accurately reflect run… #15333

Merged
merged 1 commit into from
Mar 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 30 additions & 116 deletions test/types/middleware.preposttypes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,47 +67,6 @@ schema.pre('init', function() {
expectType<HydratedDocument<IDocument>>(this);
});

schema.post('init', function(res) {
expectType<HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre('init', { document: true, query: false }, function() {
expectType<HydratedDocument<IDocument>>(this);
});

schema.post('init', { document: true, query: false }, function(res) {
expectType<HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre('init', { document: true, query: true }, function() {
expectType<HydratedDocument<IDocument>>(this);
});

schema.post('init', { document: true, query: true }, function(res) {
expectType<HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre('init', { document: false, query: true }, function() {
expectType<never>(this);
});

schema.post('init', { document: false, query: true }, function(res) {
expectType<never>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre('init', { document: false, query: false }, function() {
expectType<never>(this);
});

schema.post('init', { document: false, query: false }, function(res) {
expectType<never>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre('estimatedDocumentCount', function() {
expectType<Query<any, any>>(this);
});
Expand Down Expand Up @@ -693,51 +652,6 @@ schema.post('deleteOne', { document: false, query: false }, function(res) {
expectNotType<Query<any, any>>(res);
});

schema.pre(['save', 'init'], function() {
expectType<HydratedDocument<IDocument>>(this);
});

schema.post(['save', 'init'], function(res) {
expectType<HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['save', 'init'], { document: true, query: false }, function() {
expectType<HydratedDocument<IDocument>>(this);
});

schema.post(['save', 'init'], { document: true, query: false }, function(res) {
expectType<HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['save', 'init'], { document: true, query: true }, function() {
expectType<HydratedDocument<IDocument>>(this);
});

schema.post(['save', 'init'], { document: true, query: true }, function(res) {
expectType<HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['save', 'init'], { document: false, query: true }, function() {
expectType<never>(this);
});

schema.post(['save', 'init'], { document: false, query: true }, function(res) {
expectType<never>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['save', 'init'], { document: false, query: false }, function() {
expectType<never>(this);
});

schema.post(['save', 'init'], { document: false, query: false }, function(res) {
expectType<never>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany'], function() {
expectType<Query<any, any>>(this);
});
Expand Down Expand Up @@ -828,137 +742,137 @@ schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct
expectNotType<Query<any, any>>(res);
});

schema.pre(['save', 'init', 'updateOne', 'deleteOne', 'validate'], function() {
schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], function() {
expectType<Query<any, any>|HydratedDocument<IDocument>>(this);
});

schema.post(['save', 'init', 'updateOne', 'deleteOne', 'validate'], function(res) {
schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], function(res) {
expectType<Query<any, any>|HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: false, query: true }, function() {
schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: false, query: true }, function() {
expectType<Query<any, any>>(this);
});

schema.post(['save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: false, query: true }, function(res) {
schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: false, query: true }, function(res) {
expectType<Query<any, any>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: true, query: false }, function() {
schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: true, query: false }, function() {
expectType<HydratedDocument<IDocument>>(this);
});

schema.post(['save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: true, query: false }, function(res) {
schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: true, query: false }, function(res) {
expectType<HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: true, query: true }, function() {
schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: true, query: true }, function() {
expectType<Query<any, any>|HydratedDocument<IDocument>>(this);
});

schema.post(['save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: true, query: true }, function(res) {
schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: true, query: true }, function(res) {
expectType<Query<any, any>|HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: false, query: false }, function() {
schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: false, query: false }, function() {
expectType<never>(this);
});

schema.post(['save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: false, query: false }, function(res) {
schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: false, query: false }, function(res) {
expectType<never>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], function() {
schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'updateOne', 'deleteOne', 'validate'], function() {
expectType<Query<any, any>|HydratedDocument<IDocument>>(this);
});

schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], function(res) {
schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'updateOne', 'deleteOne', 'validate'], function(res) {
expectType<Query<any, any>|HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: false, query: true }, function() {
schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'updateOne', 'deleteOne', 'validate'], { document: false, query: true }, function() {
expectType<Query<any, any>>(this);
});

schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: false, query: true }, function(res) {
schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'updateOne', 'deleteOne', 'validate'], { document: false, query: true }, function(res) {
expectType<Query<any, any>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: true, query: false }, function() {
schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'updateOne', 'deleteOne', 'validate'], { document: true, query: false }, function() {
expectType<HydratedDocument<IDocument>>(this);
});

schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: true, query: false }, function(res) {
schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'updateOne', 'deleteOne', 'validate'], { document: true, query: false }, function(res) {
expectType<HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: true, query: true }, function() {
schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'updateOne', 'deleteOne', 'validate'], { document: true, query: true }, function() {
expectType<Query<any, any>|HydratedDocument<IDocument>>(this);
});

schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: true, query: true }, function(res) {
schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'updateOne', 'deleteOne', 'validate'], { document: true, query: true }, function(res) {
expectType<Query<any, any>|HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: false, query: false }, function() {
schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'updateOne', 'deleteOne', 'validate'], { document: false, query: false }, function() {
expectType<never>(this);
});

schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'updateOne', 'deleteOne', 'validate'], { document: false, query: false }, function(res) {
schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'updateOne', 'deleteOne', 'validate'], { document: false, query: false }, function(res) {
expectType<never>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'init', 'updateOne', 'deleteOne', 'validate'], function() {
schema.pre(['save', 'updateOne', 'deleteOne', 'validate'], function() {
expectType<Query<any, any>|HydratedDocument<IDocument>>(this);
});

schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'init', 'updateOne', 'deleteOne', 'validate'], function(res) {
schema.post(['save', 'updateOne', 'deleteOne', 'validate'], function(res) {
expectType<Query<any, any>|HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: false, query: true }, function() {
schema.pre(['save', 'updateOne', 'deleteOne', 'validate'], { document: false, query: true }, function() {
expectType<Query<any, any>>(this);
});

schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: false, query: true }, function(res) {
schema.post(['save', 'updateOne', 'deleteOne', 'validate'], { document: false, query: true }, function(res) {
expectType<Query<any, any>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: true, query: false }, function() {
schema.pre(['save', 'updateOne', 'deleteOne', 'validate'], { document: true, query: false }, function() {
expectType<HydratedDocument<IDocument>>(this);
});

schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: true, query: false }, function(res) {
schema.post(['save', 'updateOne', 'deleteOne', 'validate'], { document: true, query: false }, function(res) {
expectType<HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: true, query: true }, function() {
schema.pre(['save', 'updateOne', 'deleteOne', 'validate'], { document: true, query: true }, function() {
expectType<Query<any, any>|HydratedDocument<IDocument>>(this);
});

schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: true, query: true }, function(res) {
schema.post(['save', 'updateOne', 'deleteOne', 'validate'], { document: true, query: true }, function(res) {
expectType<Query<any, any>|HydratedDocument<IDocument>>(this);
expectNotType<Query<any, any>>(res);
});

schema.pre(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: false, query: false }, function() {
schema.pre(['save', 'updateOne', 'deleteOne', 'validate'], { document: false, query: false }, function() {
expectType<never>(this);
});

schema.post(['estimatedDocumentCount', 'countDocuments', 'deleteMany', 'distinct', 'find', 'findOne', 'findOneAndDelete', 'findOneAndReplace', 'findOneAndUpdate', 'replaceOne', 'updateMany', 'save', 'init', 'updateOne', 'deleteOne', 'validate'], { document: false, query: false }, function(res) {
schema.post(['save', 'updateOne', 'deleteOne', 'validate'], { document: false, query: false }, function(res) {
expectType<never>(this);
expectNotType<Query<any, any>>(res);
});
Expand Down
31 changes: 31 additions & 0 deletions test/types/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,37 @@ async function schemaDouble() {
expectType<Types.Double | null | undefined>(doc.balance);
}

function gh15301() {
interface IUser {
time: { hours: number, minutes: number }
}
const userSchema = new Schema<IUser>({
time: {
type: new Schema(
{
hours: { type: Number, required: true },
minutes: { type: Number, required: true }
},
{ _id: false }
),
required: true
}
});

const timeStringToObject = (time) => {
if (typeof time !== 'string') return time;
const [hours, minutes] = time.split(':');
return { hours: parseInt(hours), minutes: parseInt(minutes) };
};

userSchema.pre('init', function(rawDoc) {
expectType<IUser>(rawDoc);
if (typeof rawDoc.time === 'string') {
rawDoc.time = timeStringToObject(rawDoc.time);
}
});
}

function defaultReturnsUndefined() {
const schema = new Schema<{ arr: number[] }>({
arr: {
Expand Down
Loading
Loading