如何修改TypeScript泛型函数签名实现服务返回类型参数推断?
问题描述
我正在创建一个createService函数,第一个参数是“服务”数组,第二个参数需要自动推断这些服务的返回类型。示例如下:
const serviceOne = createService([], () => Promise.resolve({} as Service1)); const serviceTwo = createService([], () => Promise.resolve({} as Service2)); const serviceThree = createService( [serviceOne, serviceTwo], (one, two) => Promise.resolve({}), // one应被推断为Service1类型,two应被推断为Service2类型 );
目前我把参数类型设为any,函数签名如下:
function createService<T extends Service<any>[], U>(deps: T, factory: (...args: any[]) => Promise<U>) { return {} as Service<U>; } type Service<U> = { instance: U };
需要修改函数签名实现上述类型推断。
解决方案
你可以借助TypeScript的元组类型映射和条件类型,提取依赖数组中每个服务的instance类型,让工厂函数的参数自动匹配对应类型。修改后的代码如下:
type Service<U> = { instance: U; }; // 工具类型:从Service数组中提取每个元素的instance类型,组成对应顺序的元组 type ExtractServiceInstances<T extends Service<any>[]> = { [K in keyof T]: T[K] extends Service<infer U> ? U : never; }; function createService< T extends Service<any>[], U >( deps: T, factory: (...args: ExtractServiceInstances<T>) => Promise<U> ): Service<U> { return {} as Service<U>; }
关键说明
ExtractServiceInstances工具类型:遍历依赖数组的每个元素,通过infer关键字提取出每个Service的instance类型,最终生成与依赖数组顺序一致的元组类型。- 工厂函数参数类型绑定:将工厂函数的
args参数类型指定为ExtractServiceInstances<T>,TypeScript会根据传入的deps数组,自动推断出工厂函数每个参数的具体类型。 - 泛型约束保持:
T依然约束为Service<any>[],确保传入的依赖都是合法的服务实例;返回值保持Service<U>,保证服务实例的类型一致性。
验证示例
修改后类型推断会正常工作:
type Service1 = { id: number; name: string }; type Service2 = { log: (msg: string) => void }; const serviceOne = createService([], () => Promise.resolve({ id: 1, name: "test" } as Service1)); const serviceTwo = createService([], () => Promise.resolve({ log: (msg) => console.log(msg) } as Service2)); const serviceThree = createService( [serviceOne, serviceTwo], (one, two) => { // one 自动推断为 Service1 类型 console.log(one.id); // two 自动推断为 Service2 类型 two.log("hello"); return Promise.resolve({ combined: true }); } );
内容的提问来源于stack exchange,提问作者Andy Jessop
相关产品推荐
相关产品推荐

