Skip to content

Commit

Permalink
feat: extend collection functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Aybrea committed Nov 3, 2024
1 parent af238bd commit f2f0f99
Show file tree
Hide file tree
Showing 11 changed files with 312 additions and 1 deletion.
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' },
]
26 changes: 26 additions & 0 deletions docs/collection/omit-by.md
Original file line number Diff line number Diff line change
@@ -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` |
26 changes: 26 additions & 0 deletions docs/collection/omit.md
Original file line number Diff line number Diff line change
@@ -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` |
26 changes: 26 additions & 0 deletions docs/collection/pick-by.md
Original file line number Diff line number Diff line change
@@ -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` |
26 changes: 26 additions & 0 deletions docs/collection/pick.md
Original file line number Diff line number Diff line change
@@ -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` |
26 changes: 26 additions & 0 deletions docs/zh/collection/omit-by.md
Original file line number Diff line number Diff line change
@@ -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` |
26 changes: 26 additions & 0 deletions docs/zh/collection/omit.md
Original file line number Diff line number Diff line change
@@ -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` |
26 changes: 26 additions & 0 deletions docs/zh/collection/pick-by.md
Original file line number Diff line number Diff line change
@@ -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` |
26 changes: 26 additions & 0 deletions docs/zh/collection/pick.md
Original file line number Diff line number Diff line change
@@ -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` |
43 changes: 43 additions & 0 deletions src/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,46 @@ 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>(object: T, keys: K[]): Omit<T, K> {
const stringKeys = new Set(keys.map(String))
const savedKeys = Object.keys(object).filter((key) => !stringKeys.has(key)) as Array<Exclude<keyof T, K>>

return pick(object, savedKeys)
}

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>)
}
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 @@ 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({})

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

0 comments on commit f2f0f99

Please sign in to comment.