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..f235e4f --- /dev/null +++ b/docs/collection/omit-by.md @@ -0,0 +1,25 @@ +# omitBy + +Creates a new object by omitting key-value pairs based on a predicate function. + +### Usage + +```ts +import { omitBy } from 'rattail' + +const picked = omitBy({ a: 1, b: 2, c: 3 }, (value) => value > 1) +console.log(picked) // { a: 1 } +``` + +### 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..d65ce51 --- /dev/null +++ b/docs/collection/omit.md @@ -0,0 +1,25 @@ +# omit + +Creates a new object by omitting specified keys from an existing object. + +### Usage + +```ts +import { omit } from 'rattail' + +const omitted = omit({ a: 1, b: 2, c: 3 }, ['a', 'c']) +console.log(omitted) // { b: 2 } +``` + +### 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..92505e5 --- /dev/null +++ b/docs/collection/pick-by.md @@ -0,0 +1,25 @@ +# pickBy + +Creates a new object by picking key-value pairs based on a predicate function. + +### Usage + +```ts +import { pickBy } from 'rattail' + +const picked = pickBy({ a: 1, b: 2, c: 3 }, (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..aa03ae3 --- /dev/null +++ b/docs/collection/pick.md @@ -0,0 +1,25 @@ +# pick + +Creates a new object by selecting specified keys from an existing object. + +### Usage + +```ts +import { pick } from 'rattail' + +const picked = pick({ a: 1, b: 2, c: 3 }, ['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..a78cf01 --- /dev/null +++ b/docs/zh/collection/omit-by.md @@ -0,0 +1,25 @@ +# omitBy + +通过提供的谓词函数排除键值对来创建新对象。 + +### 使用 + +```ts +import { omitBy } from 'rattail' + +const picked = omitBy({ a: 1, b: 2, c: 3 }, (value) => value > 1) +console.log(picked) // { a: 1 } +``` + +### 参数 + +| 参数 | 类型 | 默认值 | +| ----------- | -------------------------------------- | ------ | +| `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..7c90355 --- /dev/null +++ b/docs/zh/collection/omit.md @@ -0,0 +1,25 @@ +# omit + +通过从现有对象中排除指定键来创建新对象。 + +### 使用 + +```ts +import { omit } from 'rattail' + +const omitted = omit({ a: 1, b: 2, c: 3 }, ['a', 'c']) +console.log(omitted) // { b: 2 } +``` + +### 参数 + +| 参数 | 类型 | 默认值 | +| -------- | ---------- | ------ | +| `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..6369e70 --- /dev/null +++ b/docs/zh/collection/pick-by.md @@ -0,0 +1,25 @@ +# pickBy + +通过提供的谓词函数选择键值对来创建新对象。 + +### 使用 + +```ts +import { pickBy } from 'rattail' + +const picked = pickBy({ a: 1, b: 2, c: 3 }, (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..928474a --- /dev/null +++ b/docs/zh/collection/pick.md @@ -0,0 +1,25 @@ +# pick + +通过从现有对象中选择指定键来创建新对象。 + +### 使用 + +```ts +import { pick } from 'rattail' + +const picked = pick({ a: 1, b: 2, c: 3 }, ['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..7a48051 100644 --- a/src/collection.ts +++ b/src/collection.ts @@ -167,3 +167,52 @@ 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(obj: T, keys: K[]): { [K2 in Exclude]: T[K2] } { + const keysToOmit = new Set(keys) + const result = {} as { [K in keyof T]: T[K] } + + ;(Object.keys(obj) as (keyof T)[]).forEach((key) => { + if (!keysToOmit.has(key as K)) { + result[key] = obj[key] + } + }) + + return result +} + +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/src/test.ts b/src/test.ts new file mode 100644 index 0000000..8ddc8d3 --- /dev/null +++ b/src/test.ts @@ -0,0 +1,4 @@ +import { omit, omitBy, pickBy } from './collection' + +const picked = omitBy({ a: 1, b: 2, c: 3 }, (value) => value > 1) +console.log(picked) // { a: 1 } 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) + }) +})