如何让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
相关产品推荐
相关产品推荐

