Typescript 笛卡尔积通用

问题描述 投票:0回答:1

这是一个打字稿笛卡尔积迭代器:

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]> {
typescript typescript-generics cartesian-product
1个回答
0
投票

要使 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 函数中:

  • T extendsknown[][] 确保函数接受数组的数组。
  • 生成器的产量类型 { [K in keyof T]: T[K] extends (infer U)[] ? U :从不 } 动态映射元组 T 以推断每个数组中包含的类型,构造一个新元组,其中每个元素对应于输入数组中元素的类型。

通过这种方式,该函数变得真正通用,可以处理任意数量的具有任何类型元素的输入数组,同时保留整个函数的类型信息。

希望可以帮助您解决问题:)

© www.soinside.com 2019 - 2024. All rights reserved.