You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用泛型声明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 entire RootCtrl instance to your document type, so find operations know exactly what shape of data to return.
  • Conditional Type: Checks if cb is undefined to decide between returning a Promise<T[]> (for promise-style calls) or void (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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:48:48