Skip to content

Commit

Permalink
fix(types): better typescript support for schema plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
emiljanitzek committed Jul 27, 2022
1 parent f5ee642 commit ca3444d
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 7 deletions.
84 changes: 84 additions & 0 deletions test/types/plugin.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { connection, HydratedDocument, Model, Query, Schema } from 'mongoose';

function pluginVirtuals(schema: Schema<Test, any, any, any, TestVirtuals>): void {
schema.virtual('fullName').get(function(this: TestDocument) {
return `${this.firstName} ${this.lastName}`;
});
schema.virtual('notDefined').get(function(this: TestDocument) {
return 'foobar';
});
}

function pluginQueryHelpers(schema: Schema<Test, any, any, TestQueryHelpers>): void {
schema.query.whereSomething = function() {
return this.where({ name: 'something' });
};
}

function pluginMethods(schema: Schema<Test, any, TestInstanceMethods>): void {
schema.methods.doSomething = function() {
return 'test';
};
}

function pluginStatics(schema: Schema<Test, TestModel, any, TestQueryHelpers, any, TestStaticMethods>): void {
schema.statics.findSomething = function() {
return this.findOne().orFail().exec();
};
schema.static({
findSomething: function() {
return this.findOne().orFail().exec();
}
});
schema.static('findSomething', function() {
return this.findOne().orFail().exec();
});
schema.static('findSomethingElse', function() {
return this.findOne();
});
}

type Test = { firstName: string; lastName: string };
type TestVirtuals = {
fullName: string;
};
interface TestInstanceMethods {
doSomething(this: TestDocument): string;
}
interface TestStaticMethods {
findSomething(this: TestModel): Promise<TestDocument>;
}
type TestDocument = HydratedDocument<Test, TestInstanceMethods, TestVirtuals>;
type TestQuery = Query<any, TestDocument, TestQueryHelpers> & TestQueryHelpers;
interface TestQueryHelpers {
whereSomething(this: TestQuery): this
}
type TestModel = Model<Test, TestQueryHelpers, TestInstanceMethods, TestVirtuals> & TestStaticMethods;
const testSchema = new Schema<Test, TestModel, TestInstanceMethods, TestQueryHelpers, TestVirtuals, TestStaticMethods>({
firstName: { type: String, required: true },
lastName: { type: String, required: true }
});

testSchema.plugin(pluginVirtuals);
testSchema.plugin(pluginQueryHelpers);
testSchema.plugin(pluginMethods);
testSchema.plugin(pluginStatics);

const Foo = connection.model<Test, TestModel, TestQueryHelpers>('Test', testSchema);

async function registerPlugin(): Promise<void> {
const test = await Foo.findOne().orFail();
console.log(test.firstName);
console.log(test.fullName);
console.log(test.doSomething());

const test2 = await Foo.findSomething();
console.log(test2.firstName);
console.log(test2.fullName);
console.log(test2.doSomething());

const test3 = await Foo.findOne().whereSomething().orFail();
console.log(test3.firstName);
console.log(test3.fullName);
console.log(test3.doSomething());
}
2 changes: 1 addition & 1 deletion types/connection.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ declare module 'mongoose' {
/** Defines or retrieves a model. */
model<T, U, TQueryHelpers = {}>(
name: string,
schema?: Schema<T, U, TQueryHelpers>,
schema?: Schema<T, U, any, TQueryHelpers, any, any>,
collection?: string,
options?: CompileModelOptions
): U;
Expand Down
18 changes: 12 additions & 6 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ declare module 'mongoose' {

export function model<T, U, TQueryHelpers = {}>(
name: string,
schema?: Schema<T, any, TQueryHelpers>,
schema?: Schema<T, any, any, TQueryHelpers>,
collection?: string,
options?: CompileModelOptions
): U;
Expand Down Expand Up @@ -157,7 +157,12 @@ declare module 'mongoose' {

type QueryResultType<T> = T extends Query<infer ResultType, any> ? ResultType : never;

export class Schema<EnforcedDocType = any, M = Model<EnforcedDocType, any, any, any>, TInstanceMethods = {}, TQueryHelpers = {}, TVirtuals = {},
export class Schema<
EnforcedDocType = any,
M = Model<EnforcedDocType, any, any, any>,
TInstanceMethods = {},
TQueryHelpers = {},
TVirtuals = {},
TStaticMethods = {},
TPathTypeKey extends TypeKeyBaseType = DefaultTypeKey,
DocType extends ObtainDocumentType<DocType, EnforcedDocType, TPathTypeKey> = ObtainDocumentType<any, EnforcedDocType, TPathTypeKey>>
Expand Down Expand Up @@ -239,7 +244,7 @@ declare module 'mongoose' {
pathType(path: string): string;

/** Registers a plugin for this schema. */
plugin(fn: (schema: Schema<DocType>, opts?: any) => void, opts?: any): this;
plugin(fn: (schema: Schema<DocType, M, TInstanceMethods, TQueryHelpers, TVirtuals, TStaticMethods>, opts?: any) => void, opts?: any): this;

/** Defines a post hook for the model. */
post<T = HydratedDocument<DocType, TInstanceMethods>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PostMiddlewareFunction<T, T>): this;
Expand Down Expand Up @@ -292,15 +297,16 @@ declare module 'mongoose' {
set<K extends keyof SchemaOptions>(key: K, value: SchemaOptions[K], _tags?: any): this;

/** Adds static "class" methods to Models compiled from this schema. */
static<K extends keyof TStaticMethods>(name: K, fn: TStaticMethods[K]): this;
static(obj: { [F in keyof TStaticMethods]: TStaticMethods[F] } & { [name: string]: (this: M, ...args: any[]) => any }): this;
static(name: string, fn: (this: M, ...args: any[]) => any): this;
static(obj: { [name: string]: (this: M, ...args: any[]) => any }): this;

/** Object of currently defined statics on this schema. */
statics: { [name: string]: (this: M, ...args: any[]) => any };
statics: { [F in keyof TStaticMethods]: TStaticMethods[F] } & { [name: string]: (this: M, ...args: any[]) => any };

/** Creates a virtual type with the given name. */
virtual<T = HydratedDocument<DocType, TInstanceMethods>>(
name: string,
name: keyof TVirtuals | string,
options?: VirtualTypeOptions<T, DocType>
): VirtualType<T>;

Expand Down

0 comments on commit ca3444d

Please sign in to comment.