Skip to content

Commit

Permalink
feat: add AutoInferredSchema to work around schema inference issues in
Browse files Browse the repository at this point in the history
  • Loading branch information
vkarpov15 committed Oct 14, 2024
1 parent f34935d commit da37597
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 7 deletions.
9 changes: 9 additions & 0 deletions lib/mongoose.js
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,15 @@ Mongoose.prototype.Mongoose = Mongoose;

Mongoose.prototype.Schema = Schema;

/**
* Identical to `Schema` at runtime. Exists purely to work around some TypeScript compatibility issues.
*
* @method AutoInferredSchema
* @api public
*/

Mongoose.prototype.AutoInferredSchema = Schema;

/**
* The Mongoose [SchemaType](https://mongoosejs.com/docs/api/schematype.html#SchemaType()) constructor
*
Expand Down
21 changes: 17 additions & 4 deletions test/types/inferrawdoctype.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { InferRawDocType } from 'mongoose';
import { InferRawDocType, Schema, AutoInferredSchema } from 'mongoose';
import { expectType, expectError } from 'tsd';

function gh14839() {
Expand All @@ -17,9 +17,22 @@ function gh14839() {
dateOfBirth: {
type: Date,
required: true
}
},
subdoc: new AutoInferredSchema({
name: { type: String, required: true },
l2: new AutoInferredSchema({
myProp: { type: Number, required: true }
})
}),
docArr: [new AutoInferredSchema({ test: { type: String, required: true } })]
};

type UserType = InferRawDocType< typeof schemaDefinition>;
expectType<{ email: string, password: string, dateOfBirth: Date }>({} as UserType);
type UserType = InferRawDocType<typeof schemaDefinition>;
expectType<{
email: string,
password: string,
dateOfBirth: Date,
subdoc?: { name: string, l2?: { myProp: number } | null } | null,
docArr: { test: string }[]
}>({} as UserType);
}
23 changes: 23 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,29 @@ declare module 'mongoose' {
TVirtuals,
TStaticMethods> = (schema: Schema<DocType, M, TInstanceMethods, TQueryHelpers, TVirtuals, TStaticMethods>, opts?: any) => void;

export class AutoInferredSchema<
SchemaDef = unknown,
RawDocType = any,
TModelType = Model<RawDocType, any, any, any>,
TInstanceMethods = {},
TQueryHelpers = {},
TVirtuals = {},
TStaticMethods = {},
TSchemaOptions = DefaultSchemaOptions,
DocType extends ApplySchemaOptions<
ObtainDocumentType<DocType, RawDocType, ResolveSchemaOptions<TSchemaOptions>>,
ResolveSchemaOptions<TSchemaOptions>
> = ApplySchemaOptions<
ObtainDocumentType<any, RawDocType, ResolveSchemaOptions<TSchemaOptions>>,
ResolveSchemaOptions<TSchemaOptions>
>,
THydratedDocumentType = HydratedDocument<FlatRecord<DocType>, TVirtuals & TInstanceMethods>
> extends Schema<RawDocType, TModelType, TInstanceMethods, TQueryHelpers, TVirtuals, TStaticMethods, TSchemaOptions, DocType, THydratedDocumentType> {
constructor(definition?: SchemaDef, options?: SchemaOptions<FlatRecord<DocType>, TInstanceMethods, TQueryHelpers, TStaticMethods, TVirtuals, THydratedDocumentType> | ResolveSchemaOptions<TSchemaOptions>);

_schemaDefinition: SchemaDef;
}

export class Schema<
RawDocType = any,
TModelType = Model<RawDocType, any, any, any>,
Expand Down
11 changes: 8 additions & 3 deletions types/inferrawdoctype.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
PathWithTypePropertyBaseType,
PathEnumOrString
} from './inferschematype';
import { InferSchemaType } from 'mongoose';

declare module 'mongoose' {
export type InferRawDocType<
Expand Down Expand Up @@ -35,6 +36,10 @@ declare module 'mongoose' {
TypeKey
>;

type InferRawDocTypeFromSchema<TSchema extends Schema> = TSchema extends AutoInferredSchema
? InferRawDocType<TSchema['_schemaDefinition']>
: InferSchemaType<TSchema>;

/**
* Same as inferSchemaType, except:
*
Expand All @@ -50,11 +55,11 @@ declare module 'mongoose' {
*/
type ResolveRawPathType<PathValueType, Options extends SchemaTypeOptions<PathValueType> = {}, TypeKey extends string = DefaultSchemaOptions['typeKey']> =
PathValueType extends Schema ?
InferSchemaType<PathValueType> :
InferRawDocTypeFromSchema<PathValueType> :
PathValueType extends (infer Item)[] ?
IfEquals<Item, never, any[], Item extends Schema ?
// If Item is a schema, infer its type.
Array<InferSchemaType<Item>> :
Array<InferRawDocTypeFromSchema<Item>> :
Item extends Record<TypeKey, any> ?
Item[TypeKey] extends Function | String ?
// If Item has a type key that's a string or a callable, it must be a scalar,
Expand All @@ -73,7 +78,7 @@ declare module 'mongoose' {
>:
PathValueType extends ReadonlyArray<infer Item> ?
IfEquals<Item, never, any[], Item extends Schema ?
Array<InferSchemaType<Item>> :
Array<InferRawDocTypeFromSchema<Item>> :
Item extends Record<TypeKey, any> ?
Item[TypeKey] extends Function | String ?
ObtainRawDocumentPathType<Item, TypeKey>[] :
Expand Down

0 comments on commit da37597

Please sign in to comment.