Repository: toss/es-toolkit
File: src/compat/array/zipWith.ts (TypeScript)

Code before:
 */
export function zipWith<T, R>(...combine: Array<((...group: T[]) => R) | ArrayLike<T> | null | undefined>): R[];
/**
 * Combines multiple arrays into a single array using a custom combiner function.
 *
 * This function takes one array and a variable number of additional arrays,
 * applying the provided combiner function to the corresponding elements of each array.
 * If the input arrays are of different lengths, the resulting array will have the length
 * of the longest input array, with undefined values for missing elements.
 *
 * @template T - The type of elements in the input arrays.
 * @template R - The type of elements in the resulting array.
 * @param {Array<((...group: T[]) => R) | ArrayLike<T> | null | undefined>} combine - The combiner function that takes corresponding elements from each array and returns a single value.
 * @returns {R[]} A new array where each element is the result of applying the combiner function to the corresponding elements of the input arrays.
 *
 * @example
 * const arr1 = [1, 2, 3];
 * const arr2 = ['a', 'b', 'c'];
 * const result = zipWith(arr1, arr2, (num, char) => `${num}${char}`);
 * // result will be ['1a', '2b', '3c']
 */
export function zipWith<T, R>(...combine: Array<((...group: T[]) => R) | ArrayLike<T> | null | undefined>): R[] {
  const length = combine.length;
  let iteratee = length > 1 ? combine[length - 1] : undefined;

  if (typeof iteratee === 'function') {
    combine.pop();
  } else {
    iteratee = undefined;
  }
  if (!combine?.length) {
    return [];
  }
  const result = unzip(combine as ArrayLike<ArrayLike<T>>);
  if (iteratee == null) {
    return result as R[];
  }
  return result.map(group => iteratee(...group)) as R[];
}


Review comment (refactor):
I'd suggest using the isFunction utility from 'src/predicate/isFunction.ts' instead of the direct typeof check here. This would maintain consistency with other type checks in the codebase.

```ts
...
if (isFunction(iteratee)) {
  combine.pop();
} else {
  iteratee = undefined;
}
```

Code after:
 * // result will be ['1a', '2b', '3c']
 */
export function zipWith<T, R>(...combine: Array<((...group: T[]) => R) | ArrayLike<T> | null | undefined>): R[];
/**
 * Combines multiple arrays into a single array using a custom combiner function.
 *
 * This function takes one array and a variable number of additional arrays,
 * applying the provided combiner function to the corresponding elements of each array.
 * If the input arrays are of different lengths, the resulting array will have the length
 * of the longest input array, with undefined values for missing elements.
 *
 * @template T - The type of elements in the input arrays.
 * @template R - The type of elements in the resulting array.
 * @param {Array<((...group: T[]) => R) | ArrayLike<T> | null | undefined>} combine - The combiner function that takes corresponding elements from each array and returns a single value.
 * @returns {R[]} A new array where each element is the result of applying the combiner function to the corresponding elements of the input arrays.
 *
 * @example
 * const arr1 = [1, 2, 3];
 * const arr2 = ['a', 'b', 'c'];
 * const result = zipWith(arr1, arr2, (num, char) => `${num}${char}`);
 * // result will be ['1a', '2b', '3c']
 */
export function zipWith<T, R>(...combine: Array<((...group: T[]) => R) | ArrayLike<T> | null | undefined>): R[] {
  const length = combine.length;
  let iteratee = length > 1 ? combine[length - 1] : undefined;

  if (isFunction(iteratee)) {
    combine.pop();
  } else {
    iteratee = undefined;
  }
  if (!combine?.length) {
    return [];
  }
  const result = unzip(combine as ArrayLike<ArrayLike<T>>);
  if (iteratee == null) {
    return result as R[];
  }
  return result.map(group => iteratee(...group)) as R[];
}