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: add pick, omit, pickBy, and omitBy functions #21

Closed
wants to merge 1 commit into from
Closed
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
4 changes: 4 additions & 0 deletions docs/.vitepress/items/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
]
25 changes: 25 additions & 0 deletions docs/collection/omit-by.md
Original file line number Diff line number Diff line change
@@ -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` |
25 changes: 25 additions & 0 deletions docs/collection/omit.md
Original file line number Diff line number Diff line change
@@ -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` |
25 changes: 25 additions & 0 deletions docs/collection/pick-by.md
Original file line number Diff line number Diff line change
@@ -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` |
25 changes: 25 additions & 0 deletions docs/collection/pick.md
Original file line number Diff line number Diff line change
@@ -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` |
25 changes: 25 additions & 0 deletions docs/zh/collection/omit-by.md
Original file line number Diff line number Diff line change
@@ -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` |
25 changes: 25 additions & 0 deletions docs/zh/collection/omit.md
Original file line number Diff line number Diff line change
@@ -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` |
25 changes: 25 additions & 0 deletions docs/zh/collection/pick-by.md
Original file line number Diff line number Diff line change
@@ -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` |
25 changes: 25 additions & 0 deletions docs/zh/collection/pick.md
Original file line number Diff line number Diff line change
@@ -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` |
49 changes: 49 additions & 0 deletions src/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,52 @@ export function cloneDeepWith<T>(value: T, fn: (value: any) => any): T {

return baseCloneDeep(value, cache)
}

export function pick<T, K extends keyof T>(object: T, keys: K[]) {
return keys.reduce(
(result, key) => {
result[key] = object[key]
return result
},
{} as Pick<T, K>,
)
}

export function omit<T extends object, K extends keyof T>(obj: T, keys: K[]): { [K2 in Exclude<keyof T, K>]: 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<T extends object>(
object: T,
predicate: (value: T[keyof T], key: keyof T) => boolean,
): Partial<T> {
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<T>)
}

export function omitBy<T extends object>(
object: T,
predicate: (value: T[keyof T], key: keyof T) => boolean,
): Partial<T> {
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<T>)
}
4 changes: 4 additions & 0 deletions src/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { omit, omitBy, pickBy } from './collection'

Check warning on line 1 in src/test.ts

View workflow job for this annotation

GitHub Actions / test

'omit' is defined but never used

Check warning on line 1 in src/test.ts

View workflow job for this annotation

GitHub Actions / test

'pickBy' is defined but never used

const picked = omitBy({ a: 1, b: 2, c: 3 }, (value) => value > 1)
console.log(picked) // { a: 1 }
58 changes: 57 additions & 1 deletion tests/collection.spec.ts
Original file line number Diff line number Diff line change
@@ -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 })
Expand Down Expand Up @@ -330,3 +330,59 @@
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({})

Check failure on line 374 in tests/collection.spec.ts

View workflow job for this annotation

GitHub Actions / test

tests/collection.spec.ts > pickBy > should return an empty object if no properties match the predicate

AssertionError: expected { d: null } to deeply equal {} - Expected + Received - Object {} + Object { + "d": null, + } ❯ tests/collection.spec.ts:374:20
})
})

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)
})
})
Loading