diff --git a/test/types/docArray.test.ts b/test/types/docArray.test.ts index ebe8092a5bb..0b23b544f13 100644 --- a/test/types/docArray.test.ts +++ b/test/types/docArray.test.ts @@ -16,6 +16,9 @@ async function gh10293() { }); const TestModel = model('gh10293TestModel', testSchema); + const doc = new TestModel(); + expectType(doc.name); + expectType(doc.arrayOfArray); testSchema.methods.getArrayOfArray = function(this: InstanceType): string[][] { // <-- function to return Array of Array const test = this.toObject(); @@ -45,7 +48,7 @@ function gh13087() { required: true, type: [Number] // [longitude, latitude] } - }, + } as const, { _id: false } ); diff --git a/test/types/document.test.ts b/test/types/document.test.ts index f4fb56fc359..55f36b6b7fc 100644 --- a/test/types/document.test.ts +++ b/test/types/document.test.ts @@ -230,6 +230,12 @@ async function gh11960() { type ParentModelType = Model; + const schemaDefinition = { + username: { type: String }, + map: { type: Map, of: String }, + nested: { type: NestedSchema }, + nestedArray: [{ type: NestedSchema }] + } as const; const ParentSchema = new Schema< Parent, ParentModelType, @@ -238,6 +244,7 @@ async function gh11960() { {}, {}, DefaultSchemaOptions, + typeof schemaDefinition, Parent, ParentDocument >({ diff --git a/test/types/querycursor.test.ts b/test/types/querycursor.test.ts index 611e9543977..47bf90257c4 100644 --- a/test/types/querycursor.test.ts +++ b/test/types/querycursor.test.ts @@ -1,7 +1,7 @@ import { Schema, model, Model, Types } from 'mongoose'; import { expectType } from 'tsd'; -const schema = new Schema({ name: { type: 'String' } }); +const schema = new Schema({ name: { type: 'String' as const } }); const Test = model('Test', schema); @@ -20,3 +20,5 @@ Test.find().cursor(). expectType(i); }). then(() => console.log('Done!')); + +expectType<{ name: { type: 'String' } }>(schema.obj); \ No newline at end of file diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index fc0204e2a71..92565dc3c0c 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -463,7 +463,7 @@ export function autoTypedSchema() { decimal1: Schema.Types.Decimal128, decimal2: 'Decimal128', decimal3: 'decimal128' - }); + } as const); type InferredTestSchemaType = InferSchemaType; @@ -483,7 +483,7 @@ export function autoTypedSchema() { const AutoTypedSchema = new Schema({ userName: { type: String, - required: [true, 'userName is required'] + required: [true, 'userName is required'] as [true, string] }, description: String, nested: new Schema({ @@ -519,7 +519,7 @@ export function autoTypedSchema() { }) ] } - }, { + } as const, { statics: { staticFn() { expectType>>(this); @@ -558,8 +558,8 @@ export type AutoTypedSchemaType = { date: Date; messages?: number; }> - } - , statics: { + }, + statics: { staticFn: () => 'Returned from staticFn' }, methods: { @@ -596,17 +596,24 @@ function gh11828() { } }; - new Schema({ + const schema = new Schema({ name: { type: String, default: () => 'Hafez' }, age: { type: Number, default: () => 27 }, bornAt: { type: Date, default: () => new Date() }, isActive: { type: Boolean, - default(): boolean { + default(this: HydratedDocument): boolean { return this.name === 'Hafez'; } } }); + + const UserModel = model('User', schema); + const doc = new UserModel(); + expectType(doc.name); + expectType(doc.age); + expectType(doc.bornAt); + expectType(doc.isActive); } function gh11997() { @@ -760,7 +767,7 @@ function pluginOptions() { } const schema = new Schema({}); - expectType>(schema.plugin(pluginFunction)); // test that chaining would be possible + expectAssignable>(schema.plugin(pluginFunction)); // test that chaining would be possible // could not add strict tests that the parameters are inferred correctly, because i dont know how this would be done in tsd @@ -1008,7 +1015,7 @@ function gh12869() { const dbExample = new Schema( { active: { type: String, enum: ['foo', 'bar'], required: true } - } + } as const ); type Example = InferSchemaType; @@ -1031,7 +1038,7 @@ function gh12882() { const arrNum = new Schema({ fooArray: { type: [{ - type: 'Number', + type: 'Number' as const, required: true }], required: true @@ -1154,6 +1161,23 @@ function gh13514() { const str: string = doc.email; } +function defaultFn() { + const schema = new Schema({ + name: String, + email: { + type: String, + // Requires `this: any` even in 7.0. + default(this: any) { + return this.name + '@test.com'; + } + } + }); + const Test = model('Test', schema); + + const doc = new Test({ name: 'john' }); + const str: string = doc.email; +} + function gh13633() { const schema = new Schema({ name: String }); @@ -1223,10 +1247,22 @@ async function gh13797() { interface IUser { name: string; } - new Schema({ name: { type: String, required: function() { - expectType(this); return true; - } } }); - new Schema({ name: { type: String, default: function() { - expectType(this); return ''; - } } }); + new Schema({ + name: { + type: String, + required: function() { + expectType(this); + return true; + } + } + }); + new Schema({ + name: { + type: String, + default: function() { + expectType(this); + return ''; + } + } + }); } diff --git a/test/types/virtuals.test.ts b/test/types/virtuals.test.ts index 0ea393eae45..654f9d9de72 100644 --- a/test/types/virtuals.test.ts +++ b/test/types/virtuals.test.ts @@ -95,14 +95,15 @@ async function autoTypedVirtuals() { const testSchema = new Schema({ email: { type: String, - required: [true, 'email is required'] + required: [true, 'email is required'] as [true, string] } }, { virtuals: { domain: { get() { expectType & AutoTypedSchemaType>(this); - return this.email.slice(this.email.indexOf('@') + 1); + const email = this.email; + return email.slice(email.indexOf('@') + 1); }, set() { expectType & AutoTypedSchemaType>(this); diff --git a/types/index.d.ts b/types/index.d.ts index 1bd4b0a7085..ee192537a3f 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -79,16 +79,16 @@ declare module 'mongoose' { collection?: string, options?: CompileModelOptions ): Model< - InferSchemaType, - ObtainSchemaGeneric, - ObtainSchemaGeneric, - ObtainSchemaGeneric, - HydratedDocument< - InferSchemaType, - ObtainSchemaGeneric & ObtainSchemaGeneric, - ObtainSchemaGeneric - >, - TSchema + InferSchemaType, + ObtainSchemaGeneric, + ObtainSchemaGeneric, + ObtainSchemaGeneric, + HydratedDocument< + InferSchemaType, + ObtainSchemaGeneric & ObtainSchemaGeneric, + ObtainSchemaGeneric + >, + TSchema > & ObtainSchemaGeneric; export function model(name: string, schema?: Schema | Schema, collection?: string, options?: CompileModelOptions): Model; @@ -223,11 +223,12 @@ declare module 'mongoose' { TVirtuals = {}, TStaticMethods = {}, TSchemaOptions = DefaultSchemaOptions, + TSchemaDefinition = any, DocType extends ApplySchemaOptions< - ObtainDocumentType>, + ObtainDocumentType>, ResolveSchemaOptions > = ApplySchemaOptions< - ObtainDocumentType>, + ObtainDocumentType>, ResolveSchemaOptions >, THydratedDocumentType = HydratedDocument @@ -236,7 +237,7 @@ declare module 'mongoose' { /** * Create a new schema */ - constructor(definition?: SchemaDefinition, EnforcedDocType> | DocType, options?: SchemaOptions | ResolveSchemaOptions); + constructor(definition?: TSchemaDefinition, options?: SchemaOptions | ResolveSchemaOptions); /** Adds key path / schema type pairs to this schema. */ add(obj: SchemaDefinition> | Schema, prefix?: string): this; @@ -300,7 +301,7 @@ declare module 'mongoose' { methods: { [F in keyof TInstanceMethods]: TInstanceMethods[F] } & AnyObject; /** The original object passed to the schema constructor */ - obj: SchemaDefinition, EnforcedDocType>; + obj: TSchemaDefinition; /** Gets/sets schema paths. */ path>(path: string): ResultType; diff --git a/types/inferschematype.d.ts b/types/inferschematype.d.ts index 75240ed1675..34d6bdb82ca 100644 --- a/types/inferschematype.d.ts +++ b/types/inferschematype.d.ts @@ -46,8 +46,8 @@ declare module 'mongoose' { * @param {TSchema} TSchema A generic of schema type instance. * @param {alias} alias Targeted generic alias. */ - type ObtainSchemaGeneric = - TSchema extends Schema + type ObtainSchemaGeneric = + TSchema extends Schema ? { EnforcedDocType: EnforcedDocType; M: M; @@ -56,6 +56,7 @@ declare module 'mongoose' { TVirtuals: TVirtuals; TStaticMethods: TStaticMethods; TSchemaOptions: TSchemaOptions; + TSchemaDefinition: TSchemaDefinition; DocType: DocType; }[alias] : unknown; @@ -76,7 +77,7 @@ declare module 'mongoose' { type IsPathDefaultUndefined = PathType extends { default: undefined } ? true : - PathType extends { default: (...args: any[]) => undefined } ? + PathType extends { default: (this: any, ...args: any[]) => undefined } ? true : false; @@ -86,13 +87,13 @@ type IsPathDefaultUndefined = PathType extends { default: undefined } * @param {TypeKey} TypeKey A generic of literal string type."Refers to the property used for path type definition". */ type IsPathRequired = - P extends { required: true | [true, string | undefined] | { isRequired: true } } | ArrayConstructor | any[] + P extends { required: true | [true, string | undefined] | { isRequired: true } } | ArrayConstructor | any[] | ReadonlyArray ? true : P extends { required: boolean } ? P extends { required: false } ? false : true - : P extends (Record) + : P extends (Record>) ? IsPathDefaultUndefined

extends true ? false : true