这是一个打字稿笛卡尔积迭代器:
export function* productIterator3<T1, T2, T3>(
...arr: [T1[], T2[], T3[]]
): Generator<[T1, T2, T3]> {
const lengths = arr.map((component) => component.length);
const total = lengths.reduce((prod, len) => prod * len, 1);
console.log(lengths, total);
for (let totalIndex = 0; totalIndex < total; totalIndex++) {
const product = [];
let reducedIndex = totalIndex;
for (const iter of arr) {
product.push(iter[reducedIndex % iter.length]);
reducedIndex = Math.floor(reducedIndex / iter.length);
}
yield product as [T1, T2, T3];
}
}
type Colors = 'blue' | 'red';
const colors: Colors[] = ['blue', 'red'];
type Sizes = 'small' | 'medium' | 'large';
const sizes: Sizes[] = ['small', 'medium', 'large'];
type Fits = 'turtleneck' | 'tank';
const fits: Fits[] = ['turtleneck', 'tank'];
for (const [color, size, fit] of productIterator3(colors, sizes, fits)) {
console.log(color, size, fit); // color, size, fit are properly typed
}
代码本身并不特定于
...arr
的长度,但打字稿注释是特定的。我如何使其完全通用?这当然不是正确的语法,但希望它能传达要点:
export function* productIterator<...T>(...arr: [...T[]]): Generator<[...T]> {
要使 productIterator 函数在 TypeScript 中完全通用,您可以使用可变元组类型,它允许您捕获元组中每个数组的类型,然后使用该信息来输入生成器的产量值。以下是如何将 productIterator3 函数调整为通用 productIterator,它可以接受任意数量的任何类型的数组:
export function* productIterator<T extends unknown[][]>(
...arr: T
): Generator<{ [K in keyof T]: T[K] extends (infer U)[] ? U : never }> {
const lengths = arr.map((component) => component.length);
const total = lengths.reduce((prod, len) => prod * len, 1);
console.log(lengths, total);
for (let totalIndex = 0; totalIndex < total; totalIndex++) {
let product: unknown[] = [];
let reducedIndex = totalIndex;
for (const iter of arr) {
product.push(iter[reducedIndex % iter.length]);
reducedIndex = Math.floor(reducedIndex / iter.length);
}
yield product as { [K in keyof T]: T[K] extends (infer U)[] ? U : never };
}
}
// Usage example
type Colors = 'blue' | 'red';
const colors: Colors[] = ['blue', 'red'];
type Sizes = 'small' | 'medium' | 'large';
const sizes: Sizes[] = ['small', 'medium', 'large'];
type Fits = 'turtleneck' | 'tank';
const fits: Fits[] = ['turtleneck', 'tank'];
for (const product of productIterator(colors, sizes, fits)) {
console.log(product); // product is properly typed
}
在此更新的 productIterator 函数中:
通过这种方式,该函数变得真正通用,可以处理任意数量的具有任何类型元素的输入数组,同时保留整个函数的类型信息。
希望可以帮助您解决问题:)