From e89d0f77681e2625b9937e12d69f121fc919c8ce Mon Sep 17 00:00:00 2001 From: Yoomin Kang Date: Sun, 2 Feb 2025 18:57:16 +0900 Subject: [PATCH 1/4] feat(pickBy): Implement compat/pickBy --- src/compat/index.ts | 1 + src/compat/object/pickBy.spec.ts | 45 ++++++++++++++++++++++++++++++++ src/compat/object/pickBy.ts | 40 ++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 src/compat/object/pickBy.spec.ts create mode 100644 src/compat/object/pickBy.ts diff --git a/src/compat/index.ts b/src/compat/index.ts index 798b24434..fde5d58a9 100644 --- a/src/compat/index.ts +++ b/src/compat/index.ts @@ -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'; diff --git a/src/compat/object/pickBy.spec.ts b/src/compat/object/pickBy.spec.ts new file mode 100644 index 000000000..64b5f22ed --- /dev/null +++ b/src/compat/object/pickBy.spec.ts @@ -0,0 +1,45 @@ +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); + }); +}); diff --git a/src/compat/object/pickBy.ts b/src/compat/object/pickBy.ts new file mode 100644 index 000000000..d4143e039 --- /dev/null +++ b/src/compat/object/pickBy.ts @@ -0,0 +1,40 @@ +/** + * 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} 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>( + obj: T, + shouldPick?: (value: T[keyof T], key: keyof T) => boolean +): Partial { + const result: Partial = {}; + + if (shouldPick === undefined) { + return obj; + } + const keys = Object.keys(obj) as Array; + 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; +} From 83d4d0aedeef8856fdce30074f73a9544f192a83 Mon Sep 17 00:00:00 2001 From: Yoomin Kang Date: Thu, 6 Feb 2025 12:45:02 +0900 Subject: [PATCH 2/4] fix: fix pickBy to return {} when obj is given as null or undefined --- src/compat/object/pickBy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compat/object/pickBy.ts b/src/compat/object/pickBy.ts index d4143e039..3b261bfe6 100644 --- a/src/compat/object/pickBy.ts +++ b/src/compat/object/pickBy.ts @@ -21,6 +21,7 @@ export function pickBy>( obj: T, shouldPick?: (value: T[keyof T], key: keyof T) => boolean ): Partial { + if (obj === null || obj === undefined) return {}; const result: Partial = {}; if (shouldPick === undefined) { From 2e78154d8ee004934c05a1a6773d6b0976390cdf Mon Sep 17 00:00:00 2001 From: Yoomin Kang Date: Thu, 6 Feb 2025 12:46:18 +0900 Subject: [PATCH 3/4] fix: fix linting error --- src/compat/object/pickBy.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compat/object/pickBy.ts b/src/compat/object/pickBy.ts index 3b261bfe6..feb75ac44 100644 --- a/src/compat/object/pickBy.ts +++ b/src/compat/object/pickBy.ts @@ -21,7 +21,9 @@ export function pickBy>( obj: T, shouldPick?: (value: T[keyof T], key: keyof T) => boolean ): Partial { - if (obj === null || obj === undefined) return {}; + if (obj === null || obj === undefined) { + return {}; + } const result: Partial = {}; if (shouldPick === undefined) { From 0c51539af7ee0e1fd5f31003e3ae08550942e2c6 Mon Sep 17 00:00:00 2001 From: Yoomin Kang Date: Thu, 6 Feb 2025 16:14:10 +0900 Subject: [PATCH 4/4] test: add tests for pickBy --- src/compat/object/pickBy.spec.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/compat/object/pickBy.spec.ts b/src/compat/object/pickBy.spec.ts index 64b5f22ed..8d6a873ee 100644 --- a/src/compat/object/pickBy.spec.ts +++ b/src/compat/object/pickBy.spec.ts @@ -42,4 +42,18 @@ describe('pickBy', () => { 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({}); + }); });