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

如何让TypeScript根据传入实体的save方法推断saveUsingTransaction的返回类型

实现saveUsingTransaction函数的返回类型自动推断

问题描述

我有一个名为saveUsingTransaction的函数,它接收一组符合TransactionActionModel接口的对象数组,这些对象必须包含一个接收SaveOptions类型参数的save方法。目前该函数的返回类型为Promise<any[]>,我希望它的返回类型能够匹配传入实体的save方法的返回类型。

例如:
当传入以下person和cat对象时:

const person = {
 phone: "0233224444",
 save: ({session}): Person => {
      return this
     }
}

const cat = {
 weight: "30kg",
 save: ({session}): Animal => {
      return this
     }
}

const results = saveUsingTransaction([person, cat])

results变量的类型应自动推断为Promise<[Person, Animal]>。

当前函数实现代码:

interface TransactionActionModel {
  save: ({ session }: SaveOptions) => any;
}


const saveUsingTransaction = async (
    newEntities: TransactionActionModel[]
  ) => {
    const returnsArray = [];
    // Create Transaction
    const session = mongoDBWrapper.client.startSession();
    try {
      // Start Transaction
      session.startTransaction({});

      for (const entity of newEntities) {
        const resolve = await entity.save({ session });
        returnsArray.push(resolve);
      }

      // End Transaction
      await session.commitTransaction();

      return returnsArray;
    } catch (error) {
      await session.abortTransaction();

      throw error;
    } finally {
      await session.endSession();
    }
  };

解决方案

可以通过泛型元组实现类型自动推断,具体修改如下:

1. 重构泛型接口

将TransactionActionModel改为泛型接口,关联save方法的返回类型,同时兼容异步返回:

interface TransactionActionModel<T> {
  save: ({ session }: SaveOptions) => T | Promise<T>;
}

2. 修改函数为泛型元组类型

调整saveUsingTransaction为泛型函数,利用元组类型保留每个输入元素的类型信息,并通过映射类型生成对应返回元组:

const saveUsingTransaction = async <T extends TransactionActionModel<any>[]>(
  newEntities: [...T] // 展开运算符确保参数被推断为元组而非普通数组
): Promise<{ [K in keyof T]: Awaited<T[K]['save'] extends (...args: any) => infer R ? R : never> }> => {
  // 显式声明返回数组的类型,避免被推断为普通数组
  const returnsArray = [] as { [K in keyof T]: Awaited<T[K]['save'] extends (...args: any) => infer R ? R : never> };
  const session = mongoDBWrapper.client.startSession();
  
  try {
    session.startTransaction({});

    // 使用索引遍历,确保每个元素的类型对应到返回数组的对应位置
    for (let i = 0; i < newEntities.length; i++) {
      const resolve = await newEntities[i].save({ session });
      returnsArray[i] = resolve;
    }

    await session.commitTransaction();
    return returnsArray;
  } catch (error) {
    await session.abortTransaction();
    throw error;
  } finally {
    await session.endSession();
  }
};

关键细节说明

  • [...T]参数类型:强制TypeScript将传入的数组推断为元组,而非宽泛的数组类型,这样才能保留每个元素的具体类型。
  • 映射返回类型:通过{ [K in keyof T]: ... }遍历元组的每个索引,用infer R提取对应元素save方法的返回类型,再通过Awaited处理异步的Promise类型,最终生成与输入元组完全对应的返回值元组类型。
  • 显式类型声明:returnsArray的类型与函数返回类型保持一致,避免TypeScript将其推断为any[]。

修改后,调用saveUsingTransaction([person, cat])时,results的类型会自动推断为Promise<[Person, Animal]>,完全符合需求。


内容的提问来源于stack exchange,提问作者Mata00616

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 17:20:57