Skip to content

Instantly share code, notes, and snippets.

@andreialecu
Last active May 14, 2020 16:03
Show Gist options
  • Save andreialecu/fb9b58a15705729eb107a706abcdd6d2 to your computer and use it in GitHub Desktop.
Save andreialecu/fb9b58a15705729eb107a706abcdd6d2 to your computer and use it in GitHub Desktop.
types mongoose patch
diff --git a/node_modules/@types/mongoose/index.d.ts b/node_modules/@types/mongoose/index.d.ts
index 7da3af8..636f644 100644
--- a/node_modules/@types/mongoose/index.d.ts
+++ b/node_modules/@types/mongoose/index.d.ts
@@ -41,6 +41,7 @@
// Richard Simko <https://github.com/richardsimko>
// Marek Tuchalski <https://github.com/ith>
// Jeremy Bensimon <https://github.com/jeremyben>
+// Andrei Alecu <https://github.com/andreialecu>
// The Half Blood Prince <https://github.com/tHBp>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// Minimum TypeScript Version: 3.2
@@ -85,9 +86,65 @@ declare module "mongoose" {
// We can use TypeScript Omit once minimum required TypeScript Version is above 3.5
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
+ type NonFunctionPropertyNames<T> = {
+ [K in keyof T]: T[K] extends Function ? never : K;
+ }[keyof T];
+
+ type NonFunctionProperties<T> = Pick<T, NonFunctionPropertyNames<T>>;
+
+ type IfEquals<X, Y, A, B> =
+ (<T>() => T extends X ? 1 : 2) extends
+ (<T>() => T extends Y ? 1 : 2) ? A : B;
+
+ type ReadonlyKeysOf<T> = {
+ [P in keyof T]: IfEquals<{ [Q in P]: T[P] }, { -readonly [Q in P]: T[P] }, never, P>
+ }[keyof T];
+
+ type OmitReadonly<T> = Omit<T, ReadonlyKeysOf<T>>;
+
+ // used to exclude functions from all levels of the schema
+ type DeepNonFunctionProperties<T> =
+ T extends Map<infer KM, infer KV>
+ // handle map values
+ // Maps are not scrubbed, replace below line with this once minimum TS version is 3.7:
+ // ? Map<KM, DeepNonFunctionProperties<KV>>
+ ? { [key: string]: DeepNonFunctionProperties<KV> } | [KM, KV][] | Map<KM, KV>
+ :
+ T extends Array<infer U>
+ ? U extends object | undefined
+ ? { [V in keyof NonFunctionProperties<OmitReadonly<U>>]: U[V] extends object | undefined
+ ? DeepNonFunctionProperties<NonNullable<U[V]>>
+ : U[V] }[]
+ : T
+ :
+ T extends object | undefined
+ ? { [V in keyof NonFunctionProperties<OmitReadonly<T>>]: T[V] extends object | undefined
+ ? DeepNonFunctionProperties<NonNullable<T[V]>>
+ : T[V] }
+ :
+ T;
+
+ // mongoose allows Map<K, V> to be specified either as a Map or a Record<K, V>
+ type DeepMapAsObject<T> = T extends object | undefined
+ ? {
+ [K in keyof T]: T[K] extends Map<infer KM, infer KV> | undefined
+ // if it's a map, transform it into Map | Record
+ // only string keys allowed
+ ? KM extends string ? Map<KM, DeepMapAsObject<KV>> | Record<KM, DeepMapAsObject<KV>> | [KM, DeepMapAsObject<KV>][] : never
+ // otherwise if it's an object or undefined (for optional props), recursively go again
+ : T[K] extends object | undefined
+ ? DeepMapAsObject<T[K]>
+ : T[K]
+ }
+ : T;
+
/* Helper type to extract a definition type from a Document type */
type DocumentDefinition<T> = Omit<T, Exclude<keyof Document, '_id'>>;
+ type ScrubCreateDefinition<T> = DeepMapAsObject<DeepNonFunctionProperties<T>>
+
+ type CreateDocumentDefinition<T> = ScrubCreateDefinition<DocumentDefinition<T>>;
+
/**
* Patched version of FilterQuery to also allow:
* - documents, ObjectId and strings for `_id`
@@ -124,6 +181,17 @@ declare module "mongoose" {
export type UpdateQuery<D> = MongooseUpdateQuery<DocumentDefinition<D>>;
+ // check whether a type consists just of {_id: T} and no other properties
+ type HasJustId<T> = keyof Omit<T, "_id"> extends never ? true : false;
+
+ // ensure that if an empty document type is passed, we allow any properties
+ // for backwards compatibility
+ export type CreateQuery<D> = HasJustId<CreateDocumentDefinition<D>> extends true
+ ? { _id?: any } & Record<string, any>
+ : D extends { _id: infer TId }
+ ? mongodb.OptionalId<CreateDocumentDefinition<D> & { _id: TId }>
+ : CreateDocumentDefinition<D>
+
/**
* Gets and optionally overwrites the function used to pluralize collection names
* @param fn function to use for pluralization of collection names
@@ -3138,11 +3206,11 @@ declare module "mongoose" {
* does new MyModel(doc).save() for every doc in docs.
* Triggers the save() hook.
*/
- create(docs: any[], callback?: (err: any, res: T[]) => void): Promise<T[]>;
- create(docs: any[], options?: SaveOptions, callback?: (err: any, res: T[]) => void): Promise<T[]>;
- create(...docs: any[]): Promise<T>;
- create(...docsWithCallback: any[]): Promise<T>;
-
+ create<TCreate = T>(doc: CreateQuery<TCreate>, options?: SaveOptions): Promise<T>;
+ create<TCreate = T>(doc: CreateQuery<TCreate>, callback?: (err: any, res: T[]) => void): Promise<T>;
+ create<TCreate = T>(docs: CreateQuery<TCreate>[], callback?: (err: any, res: T[]) => void): Promise<T[]>;
+ create<TCreate = T>(docs: CreateQuery<TCreate>[], options?: SaveOptions, callback?: (err: any, res: T[]) => void): Promise<T[]>;
+ create<TCreate = T>(...docs: CreateQuery<TCreate>[]): Promise<T>;
/**
* Create the collection for this model. By default, if no indexes are specified, mongoose will not create the
* collection for the model until any documents are created. Use this method to create the collection explicitly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment