Skip to content

Commit

Permalink
feat(compat): implement negate
Browse files Browse the repository at this point in the history
  • Loading branch information
D-Sketon committed Dec 15, 2024
1 parent becaac5 commit 3ea9dd3
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 0 deletions.
6 changes: 6 additions & 0 deletions benchmarks/performance/negate.bench.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import { bench, describe } from 'vitest';
import { negate as negateToolkit_ } from 'es-toolkit';
import { negate as negateCompatToolkit_ } from 'es-toolkit/compat';
import { negate as negateLodash_ } from 'lodash';

const negateToolkit = negateToolkit_;
const negateCompatToolkit = negateCompatToolkit_;
const negateLodash = negateLodash_;

describe('compact', () => {
bench('es-toolkit', () => {
negateToolkit(() => true)();
});

bench('es-toolkit/compat', () => {
negateCompatToolkit(() => true)();
});

bench('lodash', () => {
negateLodash(() => true)();
});
Expand Down
69 changes: 69 additions & 0 deletions src/compat/function/negate.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { describe, expect, it } from 'vitest';
import { negate } from './negate';
import { stubTrue } from '../util/stubTrue';
import { times } from '../util/times';

describe('negate', () => {
function isEven(n: number) {
return n % 2 === 0;
}
it('should create a function that negates the result of `func`', () => {
const negateFn = negate(isEven);

expect(negateFn(1)).toBe(true);
expect(negateFn(2)).toBe(false);
});

it('should create a function that negates the result of `func`', () => {
const negateFn = negate(isEven);

expect(negateFn(1)).toBe(true);
expect(negateFn(2)).toBe(false);
});

it('should create a function that accepts multiple arguments', () => {
let argCount: any;
const count = 5;
// @ts-expect-error - any
const negateFn = negate((...args: any[]) => {
argCount = args.length;
});
const expected = times(count, stubTrue);

const actual = times(count, index => {
switch (index) {
case 0:
negateFn();
break;
case 1:
negateFn(1);
break;
case 2:
negateFn(1, 2);
break;
case 3:
negateFn(1, 2, 3);
break;
case 4:
negateFn(1, 2, 3, 4);
}
return argCount === index;
});

expect(actual).toEqual(expected);
});

it('should throw an error if `func` is not a function', () => {
expect(() => negate(1 as any)).toThrow(TypeError);
});

it('should invoke `func` with the correct `this` binding', () => {
const object = { isEven };
const negateFn = negate(function (this: any, n: number) {
return this.isEven(n);
});

expect(negateFn.call(object, 1)).toBe(true);
expect(negateFn.call(object, 2)).toBe(false);
});
});
21 changes: 21 additions & 0 deletions src/compat/function/negate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Creates a function that negates the result of the predicate function.
*
* @template F - The type of the function to negate.
* @param {F} func - The function to negate.
* @returns {F} The new negated function, which negates the boolean result of `func`.
*
* @example
* const array = [1, 2, 3, 4, 5, 6];
* const isEven = (n: number) => n % 2 === 0;
* const result = array.filter(negate(isEven));
* // result will be [1, 3, 5]
*/
export function negate<F extends (...args: any[]) => boolean>(func: F): F {
if (typeof func !== 'function') {
throw new TypeError('Expected a function');
}
return function (this: any, ...args: any[]) {
return !func.apply(this, args);
} as F;
}
1 change: 1 addition & 0 deletions src/compat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export { delay } from './function/delay.ts';
export { flip } from './function/flip.ts';
export { flow } from './function/flow.ts';
export { flowRight } from './function/flowRight.ts';
export { negate } from './function/negate.ts';
export { nthArg } from './function/nthArg.ts';
export { rearg } from './function/rearg.ts';
export { rest } from './function/rest.ts';
Expand Down

0 comments on commit 3ea9dd3

Please sign in to comment.