diff --git a/docs/.vitepress/items/collection.ts b/docs/.vitepress/items/collection.ts index 38e8f21..04acacc 100644 --- a/docs/.vitepress/items/collection.ts +++ b/docs/.vitepress/items/collection.ts @@ -3,4 +3,8 @@ export const collectionItems = [ { text: 'cloneDeepWith', link: '/collection/clone-deep-with' }, { text: 'merge', link: '/collection/merge' }, { text: 'mergeWith', link: '/collection/merge-with' }, + { text: 'pick', link: '/collection/pick' }, + { text: 'omit', link: '/collection/omit' }, + { text: 'pickBy', link: '/collection/pick-by' }, + { text: 'omitBy', link: '/collection/omit-by' }, ] diff --git a/docs/collection/omit-by.md b/docs/collection/omit-by.md new file mode 100644 index 0000000..15b81c9 --- /dev/null +++ b/docs/collection/omit-by.md @@ -0,0 +1,26 @@ +# omitBy + +Creates a new object by omitting key-value pairs based on a predicate function. + +### Usage + +```ts +import { omitBy } from 'rattail' + +const obj = { a: 1, b: 2, c: 3 } +const omitted = omitBy(obj, (value) => value < 3) +console.log(omitted) // { c: 3 } +``` + +### Arguments + +| Arg | Type | Defaults | +| ----------- | -------------------------------------- | -------- | +| `object` | `object` | | +| `predicate` | `(value: any, key: string) => boolean` | | + +### Return + +| Type | +| -------- | +| `object` | diff --git a/docs/collection/omit.md b/docs/collection/omit.md new file mode 100644 index 0000000..3d0e149 --- /dev/null +++ b/docs/collection/omit.md @@ -0,0 +1,26 @@ +# omit + +Creates a new object by omitting specified keys from an existing object. + +### Usage + +```ts +import { omit } from 'rattail' + +const obj = { a: 1, b: 2, c: 3 } +const omitted = omit(obj, ['b']) +console.log(omitted) // { a: 1, c: 3 } +``` + +### Arguments + +| Arg | Type | Defaults | +| -------- | ---------- | -------- | +| `object` | `object` | | +| `keys` | `string[]` | | + +### Return + +| Type | +| -------- | +| `object` | diff --git a/docs/collection/pick-by.md b/docs/collection/pick-by.md new file mode 100644 index 0000000..9503d43 --- /dev/null +++ b/docs/collection/pick-by.md @@ -0,0 +1,26 @@ +# pickBy + +Creates a new object by picking key-value pairs based on a predicate function. + +### Usage + +```ts +import { pickBy } from 'rattail' + +const obj = { a: 1, b: 2, c: 3 } +const picked = pickBy(obj, (value) => value > 1) +console.log(picked) // { b: 2, c: 3 } +``` + +### Arguments + +| Arg | Type | Defaults | +| ----------- | -------------------------------------- | -------- | +| `object` | `object` | | +| `predicate` | `(value: any, key: string) => boolean` | | + +### Return + +| Type | +| -------- | +| `object` | diff --git a/docs/collection/pick.md b/docs/collection/pick.md new file mode 100644 index 0000000..e666d4e --- /dev/null +++ b/docs/collection/pick.md @@ -0,0 +1,26 @@ +# pick + +Creates a new object by selecting specified keys from an existing object. + +### Usage + +```ts +import { pick } from 'rattail' + +const obj = { a: 1, b: 2, c: 3 } +const picked = pick(obj, ['a', 'c']) +console.log(picked) // { a: 1, c: 3 } +``` + +### Arguments + +| Arg | Type | Defaults | +| -------- | ---------- | -------- | +| `object` | `object` | | +| `keys` | `string[]` | | + +### Return + +| Type | +| -------- | +| `object` | diff --git a/docs/zh/collection/omit-by.md b/docs/zh/collection/omit-by.md new file mode 100644 index 0000000..6392eca --- /dev/null +++ b/docs/zh/collection/omit-by.md @@ -0,0 +1,26 @@ +# omitBy + +通过提供的谓词函数排除键值对来创建新对象。 + +### 使用 + +```ts +import { omitBy } from 'rattail' + +const obj = { a: 1, b: 2, c: 3 } +const omitted = omitBy(obj, (value) => value < 3) +console.log(omitted) // { c: 3 } +``` + +### 参数 + +| 参数 | 类型 | 默认值 | +| ----------- | -------------------------------------- | ------ | +| `object` | `object` | | +| `predicate` | `(value: any, key: string) => boolean` | | + +### 返回值 + +| 类型 | +| -------- | +| `object` | diff --git a/docs/zh/collection/omit.md b/docs/zh/collection/omit.md new file mode 100644 index 0000000..e1c27e8 --- /dev/null +++ b/docs/zh/collection/omit.md @@ -0,0 +1,26 @@ +# omit + +通过从现有对象中排除指定键来创建新对象。 + +### 使用 + +```ts +import { omit } from 'rattail' + +const obj = { a: 1, b: 2, c: 3 } +const omitted = omit(obj, ['b']) +console.log(omitted) // { a: 1, c: 3 } +``` + +### 参数 + +| 参数 | 类型 | 默认值 | +| -------- | ---------- | ------ | +| `object` | `object` | | +| `keys` | `string[]` | | + +### 返回值 + +| 类型 | +| -------- | +| `object` | diff --git a/docs/zh/collection/pick-by.md b/docs/zh/collection/pick-by.md new file mode 100644 index 0000000..bddad0d --- /dev/null +++ b/docs/zh/collection/pick-by.md @@ -0,0 +1,26 @@ +# pickBy + +通过提供的谓词函数选择键值对来创建新对象。 + +### 使用 + +```ts +import { pickBy } from 'rattail' + +const obj = { a: 1, b: 2, c: 3 } +const picked = pickBy(obj, (value) => value > 1) +console.log(picked) // { b: 2, c: 3 } +``` + +### 参数 + +| 参数 | 类型 | 默认值 | +| ----------- | -------------------------------------- | ------ | +| `object` | `object` | | +| `predicate` | `(value: any, key: string) => boolean` | | + +### 返回值 + +| 类型 | +| -------- | +| `object` | diff --git a/docs/zh/collection/pick.md b/docs/zh/collection/pick.md new file mode 100644 index 0000000..436d068 --- /dev/null +++ b/docs/zh/collection/pick.md @@ -0,0 +1,26 @@ +# pick + +通过从现有对象中选择指定键来创建新对象。 + +### 使用 + +```ts +import { pick } from 'rattail' + +const obj = { a: 1, b: 2, c: 3 } +const picked = pick(obj, ['a', 'c']) +console.log(picked) // { a: 1, c: 3 } +``` + +### 参数 + +| 参数 | 类型 | 默认值 | +| -------- | ---------- | ------ | +| `object` | `object` | | +| `keys` | `string[]` | | + +### 返回值 + +| 类型 | +| -------- | +| `object` | diff --git a/src/collection.ts b/src/collection.ts index 4bb69ca..20ba2fb 100644 --- a/src/collection.ts +++ b/src/collection.ts @@ -167,3 +167,46 @@ export function cloneDeepWith(value: T, fn: (value: any) => any): T { return baseCloneDeep(value, cache) } + +export function pick(object: T, keys: K[]) { + return keys.reduce( + (result, key) => { + result[key] = object[key] + return result + }, + {} as Pick, + ) +} + +export function omit(object: T, keys: K[]): Omit { + const stringKeys = new Set(keys.map(String)) + const savedKeys = Object.keys(object).filter((key) => !stringKeys.has(key)) as Array> + + return pick(object, savedKeys) +} + +export function pickBy( + object: T, + predicate: (value: T[keyof T], key: keyof T) => boolean, +): Partial { + return Object.keys(object).reduce((result, key) => { + const typedKey = key as keyof T + if (predicate(object[typedKey], typedKey)) { + result[typedKey] = object[typedKey] + } + return result + }, {} as Partial) +} + +export function omitBy( + object: T, + predicate: (value: T[keyof T], key: keyof T) => boolean, +): Partial { + return Object.keys(object).reduce((result, key) => { + const typedKey = key as keyof T + if (!predicate(object[typedKey], typedKey)) { + result[typedKey] = object[typedKey] + } + return result + }, {} as Partial) +} diff --git a/tests/collection.spec.ts b/tests/collection.spec.ts index b95a59b..2d3fd89 100644 --- a/tests/collection.spec.ts +++ b/tests/collection.spec.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest' -import { merge, mergeWith, cloneDeep, cloneDeepWith, isNumber, hasOwn } from '../src' +import { merge, mergeWith, cloneDeep, cloneDeepWith, isNumber, hasOwn, pick, omit, pickBy, omitBy } from '../src' it('should merge two objects', () => { const result = merge({ a: 1, b: { c: 2 } }, { b: { d: 3 }, e: 4 }) @@ -330,3 +330,59 @@ describe('cloneDeepWith', () => { expect(result).toEqual({ a: 2, b: 3 }) }) }) + +const sampleObject = { + a: 1, + b: 'hello', + c: true, + d: null, + e: 5, +} + +describe('pick', () => { + it('should pick specified keys from an object', () => { + const result = pick(sampleObject, ['a', 'b']) + expect(result).toEqual({ a: 1, b: 'hello' }) + }) + + it('should return an empty object if no keys match', () => { + const result = pick(sampleObject, []) + expect(result).toEqual({}) + }) +}) + +describe('omit', () => { + it('should omit specified keys from an object', () => { + const result = omit(sampleObject, ['a', 'b']) + expect(result).toEqual({ c: true, d: null, e: 5 }) + }) + + it('should return the full object if no keys are omitted', () => { + const result = omit(sampleObject, []) + expect(result).toEqual(sampleObject) + }) +}) + +describe('pickBy', () => { + it('should pick properties based on a predicate function', () => { + const result = pickBy(sampleObject, (value) => typeof value === 'number') + expect(result).toEqual({ a: 1, e: 5 }) + }) + + it('should return an empty object if no properties match the predicate', () => { + const result = pickBy(sampleObject, (value) => typeof value === 'object') + expect(result).toEqual({}) + }) +}) + +describe('omitBy', () => { + it('should omit properties based on a predicate function', () => { + const result = omitBy(sampleObject, (value) => value === null || value === true) + expect(result).toEqual({ a: 1, b: 'hello', e: 5 }) + }) + + it('should return the full object if no properties match the predicate', () => { + const result = omitBy(sampleObject, (value) => typeof value === 'symbol') + expect(result).toEqual(sampleObject) + }) +})