No puedo convertir ese fragmento de código de Javascript a Typescript.
El problema es convertir el operador ...spread.
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 combinationsIntento de conversión a 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: un argumento de propagación debe tener un tipo de tupla o pasarse a un parámetro de descanso.
si cambio
next = calculateCombinationsTS(next, ...rest);a
next = calculateCombinationsTS(next, rest);la función me da un resultado incorrecto, porque rest se pasa como matriz de matriz en lugar de una lista de argumentos
Ejemplo de salida:
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' ] ]Hay dos problemas:
Si desea pasar una serie de argumentos de matriz para su parámetro de descanso, su parámetro de descanso debe ser una matriz de matrices, no solo una matriz. Entonces: ...rest: any[][] . TypeScript no se queja de eso porque puede usar una matriz para any , pero es un reflejo más preciso de lo que está haciendo.
TypeScript no puede decir que la llamada calculateCombinationsTS(next, ...more); pasará un argumento para next a la función, aunque tenga una verificación en rest.length y sepa que lo hará. Debe llamar a la función con dos argumentos discretos, seguidos (opcionalmente) de distribuir una matriz. Puede solucionarlo tomando el primer elemento del parámetro rest y pasándolo explícitamente:
if (rest.length) { const [first, ...more] = rest; next = calculateCombinationsTS(next, first, ...more); }En teoría, eso podría agregar gastos generales. En la práctica, sospecho que los gastos generales estarán lo suficientemente optimizados como para no ser un problema.
O, dado que sabe que la llamada es correcta (porque sabe que rest tiene al menos un elemento), podría silenciar el error con un @ts-ignore , pero trato de evitarlos donde puedo.
Función completa que soluciona ambos problemas:
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())); }Ejemplo de área de juegos ejecutable que genera las 72 combinaciones de su ejemplo
Prueba esto
next = calculateCombinationsTS(next, rest[0], ...rest.slice(1));Typescript será más feliz si llama explícitamente a la función con la misma firma (primero, siguiente, ... extendido).
El problema es cómo llamas a la función, eso no es un problema de TypeScript.
calculateCombinations quiere 2 argumentos requeridos, luego algunos otros, pero está enviando solo un argumento requerido cuando lo llama nuevamente de forma recursiva.
Cuando dices calculateCombinations(next, ...rest) TypeScript piensa a next: any[] debería ser un operador de propagación