You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将可变参数类型转换为笛卡尔积函数的指定返回类型?

实现带精确类型推导的笛卡尔积函数(支持枚举与数组)

完整修正代码

// 定义输入类型:枚举(对象)或数组
type EnumOrArray = Record<string, any> | any[];

// 工具类型:提取输入的元素类型(数组取元素,枚举取值类型)
type ExtractEnumOrArrayElement<T> = 
  T extends any[] ? T[number] :
  T extends Record<string, infer Value> ? Value :
  never;

// 可变泛型递归推导笛卡尔积结果类型
type CartesianProduct<T extends readonly EnumOrArray[]> = 
  T extends [infer First, ...infer Rest]
    ? First extends EnumOrArray
      ? [ExtractEnumOrArrayElement<First>, ...CartesianProduct<Rest>][]
      : never
    : [];

export function cartesian<T extends readonly EnumOrArray[]>(...inputs: [...T]): CartesianProduct<T> {
  const itemGroups = inputs.map(input => {
    if (Array.isArray(input)) {
      return input;
    } else {
      // 过滤枚举的数字键(反向映射),只取原始枚举值
      const originalKeys = Object.keys(input).filter(key => isNaN(Number(key)));
      return originalKeys.map(key => input[key]);
    }
  });

  function generateCartesianProduct(groups: any[][], prefix: any[] = []): any[][] {
    if (!groups.length) return [prefix];
    const firstGroup = groups[0];
    const restGroups = groups.slice(1);

    let result: any[][] = [];
    firstGroup.forEach(item => {
      result = result.concat(generateCartesianProduct(restGroups, [...prefix, item]));
    });
    return result;
  }

  return generateCartesianProduct(itemGroups) as CartesianProduct<T>;
}

关键类型逻辑说明

  1. 工具类型ExtractEnumOrArrayElement:

    • 对数组类型,直接取T[number]获取数组元素的联合类型
    • 对枚举(TS中枚举编译后是包含正向/反向映射的对象),取对象值的类型Value,和代码中提取枚举原始值的逻辑对应
  2. 可变泛型与递归类型CartesianProduct:

    • 使用T extends [infer First, ...infer Rest]解构输入元组,递归推导每一项的元素类型
    • 最终将每一项的元素类型组合成元组,再包裹成数组类型,实现[Color, number, Size][]这样的精确返回类型
  3. 函数参数的可变泛型:

    • 用...inputs: [...T]让TS将输入的多个参数推导为元组类型T,而非数组类型,确保每一项的类型都能被精准捕获

测试验证

enum Color {
  Red = 'red',
  Green = 'green',
  Blue = 'blue'
}
enum Size {
  Small = 1,
  Medium = 10,
  Large = 100
}
const numbers = [1, 2] as const; // 用as const让数组元素类型被精确推导为1|2

const combos = cartesian(Color, numbers, Size);
// 此时combos的类型为:[Color, 1 | 2, Size][]

扩展支持Set的准备

如果后续要支持Set类型,只需修改ExtractEnumOrArrayElement工具类型:

type ExtractEnumOrArrayElement<T> = 
  T extends any[] ? T[number] :
  T extends Set<infer Value> ? Value :
  T extends Record<string, infer Value> ? Value :
  never;

同时在函数的itemGroups处理逻辑中加入Set的判断:

if (input instanceof Set) {
  return Array.from(input);
}

内容的提问来源于stack exchange,提问作者Steven Lu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 20:13:20