如何使用泛型声明RootCtrl类doFindMany方法的返回值类型
Adding Generic Return Type to
doFindMany Method Let's fix this step by step to get type-safe return values for your doFindMany method, whether you're using callbacks or promises.
First, Add a Generic to the RootCtrl Class
Since your Model is already generic, we'll tie the RootCtrl to a specific document type T so all operations know what they're working with:
// First, make sure your MongoErrorCB is also generic (adjust if needed) type MongoErrorCB<T> = (err: Error | null, result: T | null) => void; export class RootCtrl<T> { m: Model<T>; constructor(m: Model<T>) { this.m = m; } }
Option 1: Use Conditional Types for Return Value
This approach keeps the method signature concise by using a conditional type to check if the callback is provided:
export class RootCtrl<T> { m: Model<T>; constructor(m: Model<T>) { this.m = m; } doFindMany( query: object, options?: CDTModelOpts, cb?: MongoErrorCB<T[]> ): cb extends undefined ? Promise<T[]> : void { const Model = this.m; const { populate, lean } = options || ({} as CDTModelOpts); let q = Model.find(query); if (populate && populate.length > 0) { q = q.populate(populate); } if (lean !== false) { q = q.lean(); } // Type assertion is needed here because TypeScript can't perfectly infer the conditional return return q.exec(cb) as any; } }
Option 2: Use Function Overloads (More Explicit)
If you prefer clearer type hints for different call patterns, function overloads are a great choice. They handle all combinations of optional parameters cleanly:
export class RootCtrl<T> { m: Model<T>; constructor(m: Model<T>) { this.m = m; } // Overload 1: With options and callback (returns void) doFindMany(query: object, options: CDTModelOpts, cb: MongoErrorCB<T[]>): void; // Overload 2: With options, no callback (returns Promise<T[]>) doFindMany(query: object, options?: CDTModelOpts): Promise<T[]>; // Overload 3: No options, with callback (returns void) doFindMany(query: object, cb: MongoErrorCB<T[]>): void; // Actual implementation doFindMany( query: object, optionsOrCb?: CDTModelOpts | MongoErrorCB<T[]>, cb?: MongoErrorCB<T[]> ): Promise<T[]> | void { const Model = this.m; let options: CDTModelOpts | undefined; // Handle parameter permutations if (typeof optionsOrCb === 'function') { cb = optionsOrCb; options = undefined; } else { options = optionsOrCb; } const { populate, lean } = options || ({} as CDTModelOpts); let q = Model.find(query); if (populate && populate.length > 0) { q = q.populate(populate); } if (lean !== false) { q = q.lean(); } if (cb) { q.exec(cb); } else { return q.exec(); } } }
How This Works
- Generic
T: Ties the entireRootCtrlinstance to your document type, sofindoperations know exactly what shape of data to return. - Conditional Type: Checks if
cbisundefinedto decide between returning aPromise<T[]>(for promise-style calls) orvoid(for callback-style calls). - Function Overloads: Explicitly defines each valid call signature, making TypeScript's autocomplete and type checking more precise without needing type assertions.
Either approach will give you the type-safe return values you're looking for!
内容的提问来源于stack exchange,提问作者Alexander Mills
相关产品推荐
相关产品推荐

