TypeScript如何从泛型数组中自动提取嵌套类型?
解决方案
要实现init函数参数的自动类型推导,核心是让TypeScript将dependencies识别为元组类型,并从每个Resource元素中提取其泛型参数。以下是针对两种构造函数结构的具体实现:
先定义基础Resource类
首先我们需要一个带有泛型的Resource基类,后续的推导都基于这个结构:
class Resource<T> { constructor(private readonly value: T) {} // 假设存在获取资源值的方法,用于在init中传递参数 getValue(): T { return this.value; } }
结构1:构造函数接收分开的dependencies和initFunction
利用元组推断和映射类型,让TS自动推导init的参数类型:
class ResourceContainer1 { constructor< // 泛型D表示dependencies的元组类型,每个元素是Resource实例 D extends Resource<any>[] >( // 使用[...D]强制TS将数组解析为元组,保留每个元素的具体类型 dependencies: [...D], // 从元组D的每个元素中提取Resource的泛型类型,组成init的参数元组 init: (...args: { [K in keyof D]: D[K] extends Resource<infer T> ? T : never }) => void ) { // 转换dependencies为对应类型的参数元组,调用init const args = dependencies.map(dep => dep.getValue()) as { [K in keyof D]: D[K] extends Resource<infer T> ? T : never }; init(...args); } } // 测试:init参数自动推导为[string, number] const strResource = new Resource("foo"); const numResource = new Resource(123); new ResourceContainer1([strResource, numResource], (str, num) => { console.log(str.toUpperCase()); // str被推断为string console.log(num.toFixed(1)); // num被推断为number });
结构2:构造函数接收包含dependencies和init的配置对象
逻辑和结构1一致,只是把参数包装在配置对象中:
class ResourceContainer2 { constructor< D extends Resource<any>[] >(config: { dependencies: [...D], init: (...args: { [K in keyof D]: D[K] extends Resource<infer T> ? T : never }) => void }) { const args = config.dependencies.map(dep => dep.getValue()) as { [K in keyof D]: D[K] extends Resource<infer T> ? T : never }; config.init(...args); } } // 测试:init参数同样自动推导为[string, number] new ResourceContainer2({ dependencies: [strResource, numResource], init: (str, num) => { console.log(str.length); // str是string console.log(num + 456); // num是number } });
关键要点
[...D]是核心:它告诉TypeScript不要把dependencies当成普通数组,而是作为元组处理,这样才能保留每个元素的具体类型信息,否则TS会将数组推断为Resource<unknown>[]之类的模糊类型。- 映射类型+
infer:通过D[K] extends Resource<infer T> ? T : never从每个Resource实例中提取其泛型参数T,组成与dependencies顺序对应的参数元组。 - 类型断言:
Array.map()返回的是普通数组,需要断言为推导后的元组类型,确保调用init时类型完全匹配。
内容的提问来源于stack exchange,提问作者Harry Burns
相关产品推荐
相关产品推荐

