Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(compat): Implement compat/pickBy #950

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/compat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ export { merge } from './object/merge.ts';
export { mergeWith } from './object/mergeWith.ts';
export { omit } from './object/omit.ts';
export { pick } from './object/pick.ts';
export { pickBy } from './object/pickBy.ts';
export { property } from './object/property.ts';
export { propertyOf } from './object/propertyOf.ts';
export { set } from './object/set.ts';
Expand Down
59 changes: 59 additions & 0 deletions src/compat/object/pickBy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { describe, expect, it } from 'vitest';
import { pickBy } from './pickBy';

describe('pickBy', () => {
it('should pick properties based on the predicate function', () => {
const obj = { a: 1, b: 'pick', c: 3 };
const shouldPick = (value: string | number) => typeof value === 'string';
const result = pickBy(obj, shouldPick);
expect(result).toEqual({ b: 'pick' });
});

it('should return an empty object if no properties satisfy the predicate', () => {
const obj = { a: 1, b: 2, c: 3 };
const shouldPick = (value: number) => typeof value === 'string';
const result = pickBy(obj, shouldPick);
expect(result).toEqual({});
});

it('should return the same object if all properties satisfy the predicate', () => {
const obj = { a: 'pick', b: 'pick', c: 'pick' };
const shouldPick = (value: string) => typeof value === 'string';
const result = pickBy(obj, shouldPick);
expect(result).toEqual(obj);
});

it('should work with an empty object', () => {
const obj = {};
const shouldPick = (value: never) => value;
const result = pickBy(obj, shouldPick);
expect(result).toEqual({});
});

it('should work with nested objects', () => {
const obj = { a: 1, b: { nested: 'pick' }, c: 3 };
const shouldPick = (value: number | { nested: string }, key: string) => key === 'b';
const result = pickBy(obj, shouldPick);
expect(result).toEqual({ b: { nested: 'pick' } });
});

it('should work with no predicate function', () => {
const obj = { a: 1, b: 'pick', c: 3 };
const result = pickBy(obj);
expect(result).toEqual(obj);
});

it('should return an empty object if the object is null', () => {
const obj = null;
const shouldPick = (value: string) => typeof value === 'string';
const result = pickBy(obj as unknown as object, shouldPick);
expect(result).toEqual({});
});

it('should return an empty object if the object is undefined', () => {
const obj = undefined;
const shouldPick = (value: string) => typeof value === 'string';
const result = pickBy(obj as unknown as object, shouldPick);
expect(result).toEqual({});
});
});
43 changes: 43 additions & 0 deletions src/compat/object/pickBy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Creates a new object composed of the properties that satisfy the predicate function.
*
* This function takes an object and a predicate function, and returns a new object that
* includes only the properties for which the predicate function returns true.
*
* @template T - The type of object.
* @param {T} obj - The object to pick properties from.
* @param {(value: T[keyof T], key: keyof T) => boolean} shouldPick - A predicate function that determines
* whether a property should be picked. It takes the property's key and value as arguments and returns `true`
* if the property should be picked, and `false` otherwise.
* @returns {Partial<T>} A new object with the properties that satisfy the predicate function.
*
* @example
* const obj = { a: 1, b: 'pick', c: 3 };
* const shouldPick = (value) => typeof value === 'string';
* const result = pickBy(obj, shouldPick);
* // result will be { b: 'pick' }
*/
export function pickBy<T extends Record<string, any>>(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi!
If you could add small fix here it would be great.

Function doesn't warn you if you pass null as obj, and if you do so, it will crash :)

however, lodash pickBy in that case returns {}
you can look here:
https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L13582

Please add same here, or some warning that obj can't be null.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your suggestion! I fixed this problem. Would you check it?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! Thank you very much)

Maybe add some tests for it? I'm not sure.

And wait for approval from someone from repo)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! I will add some tests :)

obj: T,
shouldPick?: (value: T[keyof T], key: keyof T) => boolean
): Partial<T> {
if (obj === null || obj === undefined) {
return {};
}
const result: Partial<T> = {};

if (shouldPick === undefined) {
return obj;
}
const keys = Object.keys(obj) as Array<keyof T>;
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = obj[key];

if (shouldPick(value, key)) {
result[key] = value;
}
}

return result;
}