I cannot convert that piece of code from Javascript to Typescript.

The problem is converting the ...spread operator.

function calculateCombinations(first, next, ...rest) {

  if (rest.length) {
    next = calculateCombinations(next, ...rest);
  }


  return first.flatMap(a => next.map(b => [a, b].flat()));
}


a1 = ['A', 'B']
a2 = ['+', '-']
a3 = ['1', '2']
a4 = ['X', 'Y', 'Z']
// Show possibile combinations
calculateCombinations(a1, a2, a3, a4); // give me an array of 24 combinations

Attempt to conversion to TS:

  function calculateCombinationsTS(first: any[], next: any[], ...rest: any[]) {
    if (rest.length) {
        next = calculateCombinationsTS(next, ...rest);
    }

   return first.flatMap(a => next.map(b => [a, b].flat()));
  }

TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.

If I change

 next = calculateCombinationsTS(next, ...rest);

to

 next = calculateCombinationsTS(next, rest);

the function give me a wrong result, because rest is passed as array of array instead of a list of arguments

Example of output:

nCombo = (a1 * a2 * a3 * a4) = 24 possibilities
[
  [ 'A', '+', '1', 'X' ], [ 'A', '+', '1', 'Y' ],
  [ 'A', '+', '1', 'Z' ], [ 'A', '+', '2', 'X' ],
  [ 'A', '+', '2', 'Y' ], [ 'A', '+', '2', 'Z' ],
  [ 'A', '-', '1', 'X' ], [ 'A', '-', '1', 'Y' ],
  [ 'A', '-', '1', 'Z' ], [ 'A', '-', '2', 'X' ],
  [ 'A', '-', '2', 'Y' ], [ 'A', '-', '2', 'Z' ],
  [ 'B', '+', '1', 'X' ], [ 'B', '+', '1', 'Y' ],
  [ 'B', '+', '1', 'Z' ], [ 'B', '+', '2', 'X' ],
  [ 'B', '+', '2', 'Y' ], [ 'B', '+', '2', 'Z' ],
  [ 'B', '-', '1', 'X' ], [ 'B', '-', '1', 'Y' ],
  [ 'B', '-', '1', 'Z' ], [ 'B', '-', '2', 'X' ],
  [ 'B', '-', '2', 'Y' ], [ 'B', '-', '2', 'Z' ] 
]

推荐答案

There are two issues:

  1. If you want to pass a series of array arguments for your rest parameter, you rest parameter must be an array of arrays, not just an array. So: ...rest: any[][]. TypeScript isn't complaining about that because you can use an array for any, but it's a more accurate reflection of what you're doing.

  2. TypeScript can't tell that the call calculateCombinationsTS(next, ...more); will pass an argument for next to the function, even though you have a check on rest.length and so you know it will. You need to call the function with two discrete arguments, followed (optionally) by spreading an array. You can fix that by grabbing the first element from the rest parameter and passing it explicitly:

    if (rest.length) {
        const [first, ...more] = rest;
        next = calculateCombinationsTS(next, first, ...more);
    }
    

    In theory, that might add overhead. In practice, I suspect the overhead will be sufficiently optimized to not be an issue.

    Or, since you know the call is correct (because you know rest has at least one element in it), you could silence the error with a @ts-ignore, but I try to avoid those where I can.

Complete function fixing both issues:

function calculateCombinationsTS(first: any[], next: any[], ...rest: any[][]) {
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^
   if (rest.length) {
       const [first, ...more] = rest;                        // ***
       next = calculateCombinationsTS(next, first, ...more); // ***
   }

   return first.flatMap((a) => next.map((b) => [a, b].flat()));
}

Runnable playground example generating the 72 combinations from your example

Javascript相关问答推荐

如何在react 路由 v6 的嵌套路由中获取参数?它不适用于我的项目

如何过滤双精度数组并在 React 中返回一个对象?

Vega-lite:包含多个字段值的图例标签表达式

使用滚动内容消失

在 vanilla JS 中实现react 性

在 Chart.js 中将“阈值”显示为带有标签的水平线

promise catch 中的错误不会触发全局错误处理程序

API调用在react 组件内返回一个promise 而不是数据

反转二叉树 Js Leet 问题 - 对返回的变量感到困惑

如何为生产构建 Vue 3 Vite 应用程序

使用 date-fn 适配器在 CHARTJS 中设置动态最小和最大日期

如何完全隐藏 Link React 组件?

如何克隆具有新 ID 和相同名称的数组对象?

使用对象映射在保留键的同时将对象作为props 传递

如何执行多个获取请求

使用 lodash 的Typescript 字符串插值

如何在onclick上调用函数,同时在函数外更改文本的值

我可以在画布上突出显示的正方形上捕捉这个(蓝色)div 吗?

如何同时使用 plotly_click 和 plotly_selected?

JavaScript,如何将css属性添加到新创建的元素?