Skip to content
Open
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
26 changes: 26 additions & 0 deletions benchmarks/function/tap.bench.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as _ from 'radashi'

describe('tap', () => {
bench('executing a side-effect function on a single object', () => {
const obj = { a: 1 }
_.tap(obj, value => {
value.a += 1
})
})

bench('executing a side-effect function on a large array', () => {
const largeArray = Array(1000)
.fill(null)
.map((_, idx) => ({ id: idx, value: idx * 2 }))
_.tap(largeArray, array => {
array.forEach(item => (item.value += 1))
})
})

bench('executing a side-effect function on deeply nested objects', () => {
const nestedObj = { a: { b: { c: { d: { e: 100 } } } } }
_.tap(nestedObj, obj => {
obj.a.b.c.d.e += 1
})
})
})
31 changes: 31 additions & 0 deletions docs/function/tap.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: tap
description: 'Execute a function with a given value and return the original value'
---

### Usage

Pass in a value and a function. The function is executed with the given value, allowing for side effects or mutations. The original value is returned.

```ts
import * as _ from 'radashi'

const obj = { count: 0 }
_.tap(obj, value => {
value.count += 1 // Mutating the object
})
console.log(obj) // => { count: 1 }

const arr = [1, 2, 3]
_.tap(arr, value => {
value.push(4) // Mutating the array
})
console.log(arr) // => [1, 2, 3, 4]

// Non-mutating operations do not alter the original value
const num = 10
_.tap(num, value => {
console.log(value * 2) // => 20 Side effect, but num remains unchanged
})
console.log(num) // => 10
```
30 changes: 30 additions & 0 deletions src/function/tap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Executes a provided function with the given value and returns the original value.
* If the callback modifies the value using a mutating method (e.g., `push`, `splice` for arrays),
* those changes will persist. Otherwise, the original value remains unchanged.
* This is useful for performing side effects within method chains.
*
* @template T - The type of the value.
* @param {T} value - The value to be passed to the provided function.
* @param {(value: T) => void} fn - A function that receives the value and applies side effects or performs mutations.
* @returns {T} The original value. If `T` is an object or array and the callback modifies it using a mutating method, the changes will persist.
*
* @example
* // Example 1: Logging a value within a method chain
* const result = tap({ a: 1 }, value => console.log(value)); // Output: { a: 1 }
* console.log(result); // Output: { a: 1 }
*
* @example
* // Example 2: Modifying an object inside the callback
* const result = tap({ count: 0 }, value => value.count += 1);
* console.log(result); // Output: { count: 1 }
*
* @example
* // Example 3: Modifying an array inside the callback
* const result = tap([1, 2, 3], value => value.push(4));
* console.log(result); // Output: [1, 2, 3, 4]
*/
export function tap<T>(value: T, fn: (value: T) => void): T {
fn(value)
return value
}
1 change: 1 addition & 0 deletions src/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export * from './function/always.ts'
export * from './function/castComparator.ts'
export * from './function/castMapping.ts'
export * from './function/noop.ts'
export * from './function/tap.ts'

export * from './number/clamp.ts'
export * from './number/inRange.ts'
Expand Down
41 changes: 41 additions & 0 deletions tests/function/tap.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as _ from 'radashi'

describe('tap', () => {
it('executes the provided function with the given value', () => {
let calledValue = null
const obj = { a: 1 }

_.tap(obj, value => {
calledValue = value
})

expect(calledValue).toBe(obj)
})

it('returns the original value', () => {
const obj = { a: 1 }
const result = _.tap(obj, () => {})

expect(result).toBe(obj)
})

it('allows mutation of the value inside the callback', () => {
const obj = { a: 1 }

const result = _.tap(obj, value => {
value.a += 1
})

expect(result).toEqual({ a: 2 })
})

it('works with arrays and allows modifications inside the callback', () => {
const arr = [1, 2, 3]

const result = _.tap(arr, value => {
value.push(4)
})

expect(result).toEqual([1, 2, 3, 4])
})
})