如何推断zip函数剩余参数的元素类型并生成目标元组类型?
解决Zip生成器的TypeScript类型推断问题
我需要为自己实现的zip生成器函数编写正确的类型声明,要求传入Iterable<string>和Iterable<number>时,返回类型为Generator<[string, number][]>。但之前的几种写法都无法得到正确的类型推断:
错误尝试1
declare function zip<T extends Iterable<any>[]>(...iterables: T): Generator<T>;
问题:类型推断结果为Generator<[string[], number[]]>,返回的是迭代器组成的元组数组,而非预期的元素元组数组。
错误尝试2
declare function zip< T extends Iterable<any>[], K = T extends Iterable<infer K>[] ? K : never, >(...iterables: T): Generator<[...K[]]>
问题:类型推断结果为Generator<(string | number)[]>,将所有迭代元素类型合并为联合类型,丢失了元组的结构。
错误尝试3
declare function zip<T extends Iterable<any>[]>( ...iterables: T ): Generator<[...(T extends Iterable<infer K>[] ? K : never)]>
问题:类型推断结果为Generator<any[]>,无法正确提取每个迭代器的元素类型。
正确的类型声明
通过元组映射类型对每个迭代器元素单独提取类型,可以实现预期的推断效果:
declare function zip<T extends Iterable<any>[]>( ...iterables: T ): Generator<{ [K in keyof T]: T[K] extends Iterable<infer V> ? V : never }[]>;
验证效果
declare const A: string[]; declare const B: Iterable<number>; const z = zip(A, B); // ^? const z: Generator<[string, number][]>
对于多参数场景同样适用:
declare const C: Iterable<boolean>; const z2 = zip(A, B, C); // ^? const z2: Generator<[string, number, boolean][]>
原理说明
- 使用
{ [K in keyof T]: ... }遍历元组T的每个索引,对每个迭代器类型T[K],通过Iterable<infer V>提取其迭代元素类型V。 - 最终映射得到的类型是与输入元组结构对应的元素类型元组,再将其包装为数组,作为Generator的返回值类型。
内容的提问来源于stack exchange,提问作者Robin De Schepper
相关产品推荐
相关产品推荐

