Skip to content

Commit

Permalink
Merge pull request #13699 from Automattic/vkarpov15/gh-13630
Browse files Browse the repository at this point in the history
types: add UpdateQueryKnownOnly type for stricter UpdateQuery type checking
  • Loading branch information
vkarpov15 committed Aug 8, 2023
2 parents 570be58 + df458ca commit 12ae677
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 15 deletions.
22 changes: 21 additions & 1 deletion test/types/queries.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ import {
PopulatedDoc,
FilterQuery,
UpdateQuery,
UpdateQueryKnownOnly,
ApplyBasicQueryCasting,
QuerySelector,
InferSchemaType,
ProjectionFields,
QueryOptions
} from 'mongoose';
import { ObjectId } from 'mongodb';
import { expectAssignable, expectError, expectType } from 'tsd';
import { expectAssignable, expectError, expectNotAssignable, expectType } from 'tsd';
import { autoTypedModel } from './models.test';
import { AutoTypedSchemaType } from './schema.test';

Expand Down Expand Up @@ -498,3 +499,22 @@ async function gh13224() {

expectError(UserModel.findOne().select<{ notInSchema: string }>(['name']).orFail());
}

function gh13630() {
interface User {
phone?: string;
name?: string;
nested?: {
test?: string;
}
}

expectAssignable<UpdateQueryKnownOnly<User>>({ $set: { name: 'John' } });
expectAssignable<UpdateQueryKnownOnly<User>>({ $unset: { phone: 'test' } });
expectAssignable<UpdateQueryKnownOnly<User>>({ $set: { nested: { test: 'foo' } } });
expectNotAssignable<UpdateQueryKnownOnly<User>>({ $set: { namee: 'foo' } });
expectNotAssignable<UpdateQueryKnownOnly<User>>({ $set: { 'nested.test': 'foo' } });

const x: UpdateQueryKnownOnly<User> = { $set: { name: 'John' } };
expectAssignable<UpdateQuery<User>>(x);
}
40 changes: 26 additions & 14 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -578,24 +578,24 @@ declare module 'mongoose' {

export type SortOrder = -1 | 1 | 'asc' | 'ascending' | 'desc' | 'descending';

type _UpdateQuery<TSchema> = {
type _UpdateQuery<TSchema, AdditionalProperties = AnyObject> = {
/** @see https://www.mongodb.com/docs/manual/reference/operator/update-field/ */
$currentDate?: AnyKeys<TSchema> & AnyObject;
$inc?: AnyKeys<TSchema> & AnyObject;
$min?: AnyKeys<TSchema> & AnyObject;
$max?: AnyKeys<TSchema> & AnyObject;
$mul?: AnyKeys<TSchema> & AnyObject;
$currentDate?: AnyKeys<TSchema> & AdditionalProperties;
$inc?: AnyKeys<TSchema> & AdditionalProperties;
$min?: AnyKeys<TSchema> & AdditionalProperties;
$max?: AnyKeys<TSchema> & AdditionalProperties;
$mul?: AnyKeys<TSchema> & AdditionalProperties;
$rename?: Record<string, string>;
$set?: AnyKeys<TSchema> & AnyObject;
$setOnInsert?: AnyKeys<TSchema> & AnyObject;
$unset?: AnyKeys<TSchema> & AnyObject;
$set?: AnyKeys<TSchema> & AdditionalProperties;
$setOnInsert?: AnyKeys<TSchema> & AdditionalProperties;
$unset?: AnyKeys<TSchema> & AdditionalProperties;

/** @see https://www.mongodb.com/docs/manual/reference/operator/update-array/ */
$addToSet?: AnyKeys<TSchema> & AnyObject;
$pop?: AnyKeys<TSchema> & AnyObject;
$pull?: AnyKeys<TSchema> & AnyObject;
$push?: AnyKeys<TSchema> & AnyObject;
$pullAll?: AnyKeys<TSchema> & AnyObject;
$addToSet?: AnyKeys<TSchema> & AdditionalProperties;
$pop?: AnyKeys<TSchema> & AdditionalProperties;
$pull?: AnyKeys<TSchema> & AdditionalProperties;
$push?: AnyKeys<TSchema> & AdditionalProperties;
$pullAll?: AnyKeys<TSchema> & AdditionalProperties;

/** @see https://www.mongodb.com/docs/manual/reference/operator/update-bitwise/ */
$bit?: AnyKeys<TSchema>;
Expand All @@ -618,6 +618,18 @@ declare module 'mongoose' {
*/
export type UpdateQuery<T> = _UpdateQuery<T> & AnyObject;

/**
* A more strict form of UpdateQuery that enforces updating only
* known top-level properties.
* @example
* ```ts
* function updateUser(_id: mongoose.Types.ObjectId, update: UpdateQueryKnownOnly<IUser>) {
* return User.updateOne({ _id }, update);
* }
* ```
*/
export type UpdateQueryKnownOnly<T> = _UpdateQuery<T, {}>;

export type FlattenMaps<T> = {
[K in keyof T]: FlattenProperty<T[K]>;
};
Expand Down

0 comments on commit 12ae677

Please sign in to comment.