ronantakizawa/codereview-bench huggingface dataset:
Repository: toss/es-toolkit
File: src/function/throttle.ts (TypeScript)

Code before:
 * Creates a throttled function that only invokes the provided function at most once
 * per every `throttleMs` milliseconds. Subsequent calls to the throttled function
 * within the wait time will not trigger the execution of the original function.
 *
 * @template F - The type of function.
 * @param {F} func - The function to throttle.
 * @param {number} throttleMs - The number of milliseconds to throttle executions to.
 * @returns {(...args: Parameters<F>) => void} A new throttled function that accepts the same parameters as the original function.
 *
 * @example
 * const throttledFunction = throttle(() => {
 *   console.log('Function executed');
 * }, 1000);
 *
 * // Will log 'Function executed' immediately
 * throttledFunction();
 *
 * // Will not log anything as it is within the throttle time
 * throttledFunction();
 *
 * // After 1 second
 * setTimeout(() => {
 *   throttledFunction(); // Will log 'Function executed'
 * }, 1000);
 */
export function throttle<F extends (...args: Parameters<F>) => ReturnType<F>>(
  func: F,
  throttleMs: number
): (...args: Parameters<F>) => void {
  let lastCallTime: number | null;

  const throttledFunction = function (...args: Parameters<F>) {
    const now = Date.now();

    if (lastCallTime == null || now - lastCallTime >= throttleMs) {
      lastCallTime = now;
      func(...args);
    }
  };

  return throttledFunction;
}


Review comment (suggestion):
```suggestion
export function throttle<F extends (...args: any[]) => void>(
```

I think `F` should extend `(...args: any[]) => void` here; Otherwise it references itself.

Code after:
 * Creates a throttled function that only invokes the provided function at most once
 * per every `throttleMs` milliseconds. Subsequent calls to the throttled function
 * within the wait time will not trigger the execution of the original function.
 *
 * @template F - The type of function.
 * @param {F} func - The function to throttle.
 * @param {number} throttleMs - The number of milliseconds to throttle executions to.
 * @returns {(...args: Parameters<F>) => void} A new throttled function that accepts the same parameters as the original function.
 *
 * @example
 * const throttledFunction = throttle(() => {
 *   console.log('Function executed');
 * }, 1000);
 *
 * // Will log 'Function executed' immediately
 * throttledFunction();
 *
 * // Will not log anything as it is within the throttle time
 * throttledFunction();
 *
 * // After 1 second
 * setTimeout(() => {
 *   throttledFunction(); // Will log 'Function executed'
 * }, 1000);
 */
export function throttle<F extends (...args: any[]) => void>(
  func: F,
  throttleMs: number
): (...args: Parameters<F>) => void {
  let lastCallTime: number | null;

  const throttledFunction = function (...args: Parameters<F>) {
    const now = Date.now();

    if (lastCallTime == null || now - lastCallTime >= throttleMs) {
      lastCallTime = now;
      func(...args);
    }
  };

  return throttledFunction;
}
Repository: toss/es-toolkit
File: src/function/ary.ts (TypeScript)

Code before:
/**
 * Creates a function that invokes func, with up to n arguments, ignoring any additional arguments.
 *
 * @template F - The type of the function.
 * @param {F} func - The function to cap arguments for.
 * @param {number} n - The arity cap.
 * @returns {(...args: any[]) => ReturnType<F>} Returns the new capped function.
 *
 * @example
 * function fn(a: number, b: number, c: number) {
 *   return Array.from(arguments);
 * }
 *
 * expect(ary(fn, 0)(1, 2, 3)).toEqual([]);
 * expect(ary(fn, 1)(1, 2, 3)).toEqual([1]);
 * expect(ary(fn, 2)(1, 2, 3)).toEqual([1, 2]);
 * expect(ary(fn, 3)(1, 2, 3)).toEqual([1, 2, 3]);
 */
export function ary<F extends (...args: any[]) => any>(func: F, n: number): (...args: any[]) => ReturnType<F> {
  return function (this: any, ...args: Parameters<F>) {
    return func.apply(this, args.slice(0, n));
  };
}


Review comment (suggestion):
```suggestion
 * ary(fn, 0)(1, 2, 3) // []
 * ary(fn, 1)(1, 2, 3) // [1]
 * ary(fn, 2)(1, 2, 3) // [1, 2]
 * ary(fn, 3)(1, 2, 3) // [1, 2, 3]
```

Code after:
/**
 * Creates a function that invokes func, with up to n arguments, ignoring any additional arguments.
 *
 * @template F - The type of the function.
 * @param {F} func - The function to cap arguments for.
 * @param {number} n - The arity cap.
 * @returns {(...args: any[]) => ReturnType<F>} Returns the new capped function.
 *
 * @example
 * function fn(a: number, b: number, c: number) {
 *   return Array.from(arguments);
 * }
 *
 * ary(fn, 0)(1, 2, 3) // []
 * ary(fn, 1)(1, 2, 3) // [1]
 * ary(fn, 2)(1, 2, 3) // [1, 2]
 * ary(fn, 3)(1, 2, 3) // [1, 2, 3]
 */
export function ary<F extends (...args: any[]) => any>(func: F, n: number): (...args: any[]) => ReturnType<F> {
  return function (this: any, ...args: Parameters<F>) {
    return func.apply(this, args.slice(0, n));
  };
}
Repository: toss/es-toolkit
File: benchmarks/performance/repeat.bench.ts (TypeScript)

Code before:
import { bench, describe } from 'vitest';
import { repeat as randomToolkit } from 'es-toolkit/compat';
import { repeat as randomLodash } from 'lodash';

describe('random', () => {
  bench('es-toolkit/repeat', () => {
    randomToolkit('abc', 2);
  });

  bench('lodash/repeat', () => {
    randomLodash('abc', 2);
  });
});


Review comment (suggestion):
```suggestion
import { repeat as repeatToolkit } from 'es-toolkit/compat';
import { repeat as repeatLodash } from 'lodash';

describe('random', () => {
  bench('es-toolkit/repeat', () => {
    repeatToolkit('abc', 2);
  });

  bench('lodash/repeat', () => {
    repeatLodash('abc', 2);
  });
```

> Hi there, Im just passerby. First of all, thank you for your great work 👍 

I wonder why you named it random, not repeat 🤔 

Code after:
import { bench, describe } from 'vitest';
import { repeat as repeatToolkit } from 'es-toolkit/compat';
import { repeat as repeatLodash } from 'lodash';

describe('repeat', () => {
  bench('es-toolkit/repeat', () => {
    repeatToolkit('abc', 2);
  });

  bench('lodash/repeat', () => {
    repeatLodash('abc', 2);
  });
});
Repository: toss/es-toolkit
File: src/array/countBy.ts (TypeScript)

Code before:
/**
 * Count the occurrences of each item in an array
 * based on a transformation function.
 *
 * This function takes an array and a transformation function
 * that converts each item in the array to a key. It then
 * counts the occurrences of each transformed item and returns
 * an object with the transformed items as keys and the counts
 * as values.
 *
 * @template T - The type of the items in the input array.
 * @template K - The type of keys.
 * @param {T[]} arr - The input array to count occurrences.
 * @param {(item: T) => K} mapper - The transformation function that maps each item to a key.
 * @returns {Record<K, number>} An object containing the transformed items as keys and the
 * counts as values.
 *
 * @example
 * const array = ['a', 'b', 'c', 'a', 'b', 'a'];
 * const result = countBy(array, String);
 * // result will be { a: 3, b: 2, c: 1 }
 *
 * @example
 * const array = [1, 2, 3, 4, 5];
 * const result = countBy(array, item => item % 2 === 0 ? 'even' : 'odd');
 * // result will be { odd: 3, even: 2 }
 */
export function countBy<T, K extends PropertyKey>(arr: readonly T[], mapper: (item: T) => K): Record<K, number> {
  const result = {} as Record<K, number>;

  for (const item of arr) {
    const key = mapper(item);

    result[key] = (result[key] ?? 0) + 1;
  }

  return result;
}


Review comment (suggestion):
```suggestion
 * const result = countBy(array, x => x);
```

Code after:
/**
 * Count the occurrences of each item in an array
 * based on a transformation function.
 *
 * This function takes an array and a transformation function
 * that converts each item in the array to a key. It then
 * counts the occurrences of each transformed item and returns
 * an object with the transformed items as keys and the counts
 * as values.
 *
 * @template T - The type of the items in the input array.
 * @template K - The type of keys.
 * @param {T[]} arr - The input array to count occurrences.
 * @param {(item: T) => K} mapper - The transformation function that maps each item to a key.
 * @returns {Record<K, number>} An object containing the transformed items as keys and the
 * counts as values.
 *
 * @example
 * const array = ['a', 'b', 'c', 'a', 'b', 'a'];
 * const result = countBy(array, x => x);
 * // result will be { a: 3, b: 2, c: 1 }
 *
 * @example
 * const array = [1, 2, 3, 4, 5];
 * const result = countBy(array, item => item % 2 === 0 ? 'even' : 'odd');
 * // result will be { odd: 3, even: 2 }
 */
export function countBy<T, K extends PropertyKey>(arr: readonly T[], mapper: (item: T) => K): Record<K, number> {
  const result = {} as Record<K, number>;

  for (const item of arr) {
    const key = mapper(item);

    result[key] = (result[key] ?? 0) + 1;
  }

  return result;
}
Repository: toss/es-toolkit
File: src/compat/string/toString.ts (TypeScript)

Code before:
/**
 *  Converts value to a string.
 *  An empty string is returned for `null` and `undefined` values.
 *  The sign of `-0` is preserved.
 *
 * @param {unknown} value - The value to convert.
 * @returns {string} Returns the converted string.
 *
 * @example
 * toString(null) // returns ''
 * toString(undefined) // returns ''
 * toString(-0) // returns '-0'
 * toString([1, 2, -0]) // returns '1,2,-0'
 * toString([Symbol('a'), Symbol('b')]) // returns 'Symbol(a),Symbol(b)'
 */
export function toString(value?: unknown): string {
  if (value == null) {
    return '';
  }

  if (Array.isArray(value)) {
    return value.map(toString).join(',');
  }

  const result = String(value);

  if (result === '0' && Object.is(Number(value), -0)) {
    return '-0';
  }

Review comment (suggestion):
```suggestion
 * Converts `value` to a string.
 *
 * An empty string is returned for `null` and `undefined` values.
 * The sign of `-0` is preserved.
```

Code after:
/**
 * Converts `value` to a string.
 *
 * An empty string is returned for `null` and `undefined` values.
 * The sign of `-0` is preserved.
 *
 * @param {unknown} value - The value to convert.
 * @returns {string} Returns the converted string.
 *
 * @example
 * toString(null) // returns ''
 * toString(undefined) // returns ''
 * toString(-0) // returns '-0'
 * toString([1, 2, -0]) // returns '1,2,-0'
 * toString([Symbol('a'), Symbol('b')]) // returns 'Symbol(a),Symbol(b)'
 */
export function toString(value?: unknown): string {
  if (value == null) {
    return '';
  }

  if (Array.isArray(value)) {
    return value.map(toString).join(',');
  }

  const result = String(value);

  if (result === '0' && Object.is(Number(value), -0)) {
    return '-0';
Repository: toss/es-toolkit
File: src/compat/_internal/normalizeForCase.ts (TypeScript)

Code before:
import { toString } from '../string/toString';

export function normalizeForCase(str: unknown): string {
  // Coerce to string
  if (typeof str !== 'string') {
    str = toString(str);
  }

  // Remove constraction apostrophes
  return (str as string).replace(/['\u2019]/g, '');
}


Review comment (suggestion):
```suggestion
import { toString } from '../util/toString';
```

Code after:
import { toString } from '../util/toString';

export function normalizeForCase(str: unknown): string {
  // Coerce to string
  if (typeof str !== 'string') {
    str = toString(str);
  }

  // Remove constraction apostrophes
  return (str as string).replace(/['\u2019]/g, '');
}
Repository: toss/es-toolkit
File: src/predicate/isNaN.ts (TypeScript)

Code before:
/**
 * Checks if the value is NaN.
 *
 * @param {unknown} value - The value to check.
 * @returns {value is typeof NaN} `true` if the value is NaN, `false` otherwise.
 *
 * @example
 * isNaN(NaN); // true
 * isNaN(0); // false
 * isNaN('NaN'); // false
 * isNaN(undefined); // false
 */
export function isNaN(value: unknown): value is typeof NaN {
  return typeof value === 'number' && value !== value;
}


Review comment (performance):
What about we use `Number.isNaN` in this case? We should check the performance differences, though..

Code after:
/**
 * Checks if the value is NaN.
 *
 * @param {unknown} value - The value to check.
 * @returns {value is typeof NaN} `true` if the value is NaN, `false` otherwise.
 *
 * @example
 * isNaN(NaN); // true
 * isNaN(0); // false
 * isNaN('NaN'); // false
 * isNaN(undefined); // false
 */
export function isNaN(value: unknown): value is typeof NaN {
  return Number.isNaN(value);
}
Repository: toss/es-toolkit
File: src/string/constantCase.ts (TypeScript)

Code before:
import { getWords } from './_internal/getWords.ts';

/**
 * Converts a string to constant case.
 *
 * Snake case is the naming convention in which each word is written in lowercase and separated by an underscore (_) character.
 *
 * @param {string} str - The string that is to be changed to constant case.
 * @returns {string} - The converted string to constant case.
 *
 * @example
 * const convertedStr1 = constantCase('camelCase') // returns 'CAMEL_CASE'
 * const convertedStr2 = constantCase('some whitespace') // returns 'SOME_WHITESPACE'
 * const convertedStr3 = constantCase('hyphen-text') // returns 'HYPHEN_TEXT'
 * const convertedStr4 = constantCase('HTTPRequest') // returns 'HTTP_REQUEST'
 */

export function constantCase(str: string): string {
  const words = getWords(str);
  return words.map(word => word.toUpperCase()).join('_');
}


Review comment (suggestion):
```suggestion
 * Constant case is a naming convention where each word is written in uppercase letters and separated by an underscore (`_`). For example, `CONSTANT_CASE`.
```

Code after:
import { getWords } from './_internal/getWords.ts';

/**
 * Converts a string to constant case.
 *
 * Constant case is a naming convention where each word is written in uppercase letters and separated by an underscore (`_`). For example, `CONSTANT_CASE`.
 *
 * @param {string} str - The string that is to be changed to constant case.
 * @returns {string} - The converted string to constant case.
 *
 * @example
 * const convertedStr1 = constantCase('camelCase') // returns 'CAMEL_CASE'
 * const convertedStr2 = constantCase('some whitespace') // returns 'SOME_WHITESPACE'
 * const convertedStr3 = constantCase('hyphen-text') // returns 'HYPHEN_TEXT'
 * const convertedStr4 = constantCase('HTTPRequest') // returns 'HTTP_REQUEST'
 */

export function constantCase(str: string): string {
  const words = getWords(str);
  return words.map(word => word.toUpperCase()).join('_');
}
Repository: toss/es-toolkit
File: benchmarks/performance/invertBy.bench.ts (TypeScript)

Code before:
import { bench, describe } from 'vitest';
import { invertBy as invertByWithCompatToolkit } from 'es-toolkit/compat';
import { invertBy as invertByWithLodash } from 'lodash';

const object = { a: 1, b: 2, c: 1, d: 4 };

describe('invertBy', () => {
  bench('lodash/invertBy', () => {
    invertByWithLodash(object);
  });

  bench('es-toolkit/compat/invertByWithCompatToolkit', () => {
    invertByWithCompatToolkit(object);
  });
});


Review comment (suggestion):
```suggestion
  bench('es-toolkit/compat/invertBy', () => {
```

Code after:
import { bench, describe } from 'vitest';
import { invertBy as invertByWithCompatToolkit } from 'es-toolkit/compat';
import { invertBy as invertByWithLodash } from 'lodash';

const object = { a: 1, b: 2, c: 1, d: 4 };

describe('invertBy', () => {
  bench('lodash/invertBy', () => {
    invertByWithLodash(object);
  });

  bench('es-toolkit/compat/invertBy', () => {
    invertByWithCompatToolkit(object);
  });
});
Repository: toss/es-toolkit
File: src/compat/predicate/isFinite.ts (TypeScript)

Code before:
/**
 * Checks if `value` is finite value.
 *
 * @param {unknown} value The value to check.
 * @returns {value is number} Returns `true` if `value` is finite value, `false` otherwise.
 *
 * @example
 * ```typescript
 * const value1 = 100;
 * const value2 = Infinity;
 * const value3 = '100';
 *
 * console.log(isFinite(value1)); // true
 * console.log(isFinite(value2)); // false
 * console.log(isFinite(value3)); // false
 * ```
 */
export function isFinite(value: unknown): value is number {
  return Number.isFinite(value);
}


Review comment (suggestion):
```suggestion
 * Checks if `value` is a finite number.
```

Code after:
/**
 * Checks if `value` is a finite number.
 *
 * @param {unknown} value The value to check.
 * @returns {value is number} Returns `true` if `value` is a finite number, `false` otherwise.
 *
 * @example
 * ```typescript
 * const value1 = 100;
 * const value2 = Infinity;
 * const value3 = '100';
 *
 * console.log(isFinite(value1)); // true
 * console.log(isFinite(value2)); // false
 * console.log(isFinite(value3)); // false
 * ```
 */
export function isFinite(value: unknown): value is number {
  return Number.isFinite(value);
}
Repository: toss/es-toolkit
File: src/compat/predicate/isFinite.ts (TypeScript)

Code before:
/**
 * Checks if `value` is finite value.
 *
 * @param {unknown} value The value to check.
 * @returns {value is number} Returns `true` if `value` is finite value, `false` otherwise.
 *
 * @example
 * ```typescript
 * const value1 = 100;
 * const value2 = Infinity;
 * const value3 = '100';
 *
 * console.log(isFinite(value1)); // true
 * console.log(isFinite(value2)); // false
 * console.log(isFinite(value3)); // false
 * ```
 */
export function isFinite(value: unknown): value is number {
  return Number.isFinite(value);
}


Review comment (suggestion):
```suggestion
 * @returns {value is number} Returns `true` if `value` is a finite number, `false` otherwise.
```

Code after:
/**
 * Checks if `value` is a finite number.
 *
 * @param {unknown} value The value to check.
 * @returns {value is number} Returns `true` if `value` is a finite number, `false` otherwise.
 *
 * @example
 * ```typescript
 * const value1 = 100;
 * const value2 = Infinity;
 * const value3 = '100';
 *
 * console.log(isFinite(value1)); // true
 * console.log(isFinite(value2)); // false
 * console.log(isFinite(value3)); // false
 * ```
 */
export function isFinite(value: unknown): value is number {
  return Number.isFinite(value);
}
Repository: toss/es-toolkit
File: src/compat/array/filter.ts (TypeScript)

Code before:
 *
 * filter({ item1: { a: 0, b: true }, item2: { a: 1, b: true }, item3: { a: 2, b: false }}, { b: false })
 * // => [{ a: 2, b: false }]
 *
 * filter([{ a: 1 }, { a: 2 }, { a: 3 }], ['a', 2]);
 * // => [{ a: 2 }]
 */
export function filter<T>(
  source: T[] | Record<any, any>,
  predicate?: ((item: T, index: number, arr: any) => unknown) | Partial<T> | [keyof T, unknown] | string
): T[] {
  if (!predicate) {
    predicate = identity;
  }

  const collection = isArray(source) ? source : Object.values(source);

  switch (typeof predicate) {
    case 'function': {
      if (!Array.isArray(source)) {
        const result: T[] = [];
        const entries: any[] = Object.entries(source);

        for (let i = 0; i < entries.length; i++) {
          const entry = entries[i];
          const [key, value] = entry;

          if (predicate(value, key, source)) {
            result.push(value);
          }
        }

        return result;
      }

      return collection.filter(predicate);
    }
    case 'object': {
      return isArray(predicate)
        ? collection.filter(matchesProperty(predicate[0], predicate[1]))
        : collection.filter(matches(predicate));
    }
    case 'string': {
      return collection.filter(property(predicate));
    }
  }
}


Review comment (performance):
```suggestion
          const key = entry[0];
          const value = entry[1];
```
We're accessing `key` and `value` with indices for performance reasons.

Code after:
 *
 * filter({ item1: { a: 0, b: true }, item2: { a: 1, b: true }, item3: { a: 2, b: false }}, { b: false })
 * // => [{ a: 2, b: false }]
 *
 * filter([{ a: 1 }, { a: 2 }, { a: 3 }], ['a', 2]);
 * // => [{ a: 2 }]
 */
export function filter<T>(
  source: T[] | Record<any, any>,
  predicate?: ((item: T, index: number, arr: any) => unknown) | Partial<T> | [keyof T, unknown] | string
): T[] {
  if (!predicate) {
    predicate = identity;
  }

  const collection = isArray(source) ? source : Object.values(source);

  switch (typeof predicate) {
    case 'function': {
      if (!Array.isArray(source)) {
        const result: T[] = [];
        const entries: any[] = Object.entries(source);

        for (let i = 0; i < entries.length; i++) {
          const entry = entries[i];
          const key = entry[0];
          const value = entry[1];

          if (predicate(value, key, source)) {
            result.push(value);
          }
        }

        return result;
      }

      return collection.filter(predicate);
    }
    case 'object': {
      return isArray(predicate)
        ? collection.filter(matchesProperty(predicate[0], predicate[1]))
        : collection.filter(matches(predicate));
    }
    case 'string': {
      return collection.filter(property(predicate));
    }
  }
}
Repository: toss/es-toolkit
File: src/compat/object/defaults.ts (TypeScript)

Code before:
import { eq } from '../_internal/eq';

/**
 * Assigns own and inherited enumerable string keyed properties of source objects to the destination object for all destination properties that resolve to `undefined`.
 *
 * Source objects are applied from left to right. Once a property is set, additional values of the same property are ignored.
 * It ensures that the destination object is not `null` or `undefined`.
 *
 * Note: This method mutates a first argument `object`.
 *
 * @template T - The destination object type.
 * @param {T} object - The destination object.
 * @returns {NonNullable<T>} Returns `object`, ensuring that the destination object is not `null` or `undefined`.
 */
export function defaults<T extends object>(object: T): NonNullable<T>;
/**
 * Assigns own and inherited enumerable string keyed properties of source objects to the destination object for all destination properties that resolve to `undefined`.
 *
 * Source objects are applied from left to right. Once a property is set, additional values of the same property are ignored.
 * It ensures that the destination object is not `null` or `undefined`.
 *
 * Note: This method mutates a first argument `object`.
 *
 * @template T - The destination object type.
 * @template S - The source object type.
 * @param {T} object - The destination object.

Review comment (suggestion):
```suggestion
import { eq } from '../util/eq.ts';
```

Code after:
import { eq } from '../util/eq.ts';

/**
 * Assigns own and inherited enumerable string keyed properties of source objects to the destination object for all destination properties that resolve to `undefined`.
 *
 * Source objects are applied from left to right. Once a property is set, additional values of the same property are ignored.
 * It ensures that the destination object is not `null` or `undefined`.
 *
 * Note: This method mutates a first argument `object`.
 *
 * @template T - The destination object type.
 * @param {T} object - The destination object.
 * @returns {NonNullable<T>} Returns `object`, ensuring that the destination object is not `null` or `undefined`.
 */
export function defaults<T extends object>(object: T): NonNullable<T>;

/**
 * Assigns own and inherited enumerable string keyed properties of source objects to the destination object for all destination properties that resolve to `undefined`.
 *
 * Source objects are applied from left to right. Once a property is set, additional values of the same property are ignored.
 * It ensures that the destination object is not `null` or `undefined`.
 *
 * Note: This method mutates a first argument `object`.
 *
 * @template T - The destination object type.
 * @template S - The source object type.