Releases: radashi-org/radashi
v12.5.1
Fixed
- (set) Avoid mutating nested objects without first cloning them by @aleclarson in fc3c7c9
- (set) Prevent prototype pollution by @aleclarson in 8147abc
v12.5.0
New Functions
Add concat
function #388
Flattens and filters nullish values from arguments.
import { concat } from 'radashi'
const result = concat('a', null, ['b', undefined], 'c')
// => ['a', 'b', 'c']
Add pluck
function #376
Map an array of objects to an array of arrays.
import { pluck } from 'radashi'
const gods = [
{ name: 'Ra', power: 100 },
{ name: 'Zeus', power: 98 },
]
const names = pluck(gods, ['name'])
// => [['Ra'], ['Zeus']]
Thanks to @nusohiro for the contribution!
Fixed
Fix mapify
index argument #384
Ensure the index argument passed to mapify
's 2nd callback is the actual array index.
import { mapify } from 'radashi'
const list = [
{ id: 'a', word: 'hello' },
{ id: 'a', word: 'bye' },
{ id: 'a', word: 'oh' },
]
const result = mapify(
list,
x => x.id,
(x, i) => x.word + i,
)
// => Map { 'a' => 'oh2' }
Thanks to @Yukiniro for the contribution!
Avoid infinite loop in cluster
when size is 0
#397
The cluster
function now correctly handles the case where the size is 0
or less by returning an empty array.
import { cluster } from 'radashi'
const result = cluster([1, 2, 3], 0)
// => []
Thanks to @fResult for the contribution!
Types
Improve cluster
type inference #389
The cluster
function now provides precise type inference for common cluster sizes (1-8) using tuple types.
import { cluster } from 'radashi'
const result = cluster(['a', 'b', 'c', 'd'], 2)
// ^? [string, string][]
Thanks to @fResult for the contribution!
v12.4.0
New Functions
Add remove
function β PR #344
The remove
function removes elements from an array based on the specified predicate function.
- Removes elements that satisfy the predicate function.
- Returns a new array with the removed elements.
- Does not mutate the original array.
import * as _ from 'radashi'
const numbers = [1, 2, 3, 4, 5]
const removed = _.remove(numbers, value => value % 2 === 0)
console.log(removed) // Output: [1, 3, 5]
Thanks to nusohiro for their work on this feature!
Add toResult
function β PR #375
The toResult
function converts a PromiseLike
to a Promise<Result>
.
- Converts a resolved promise to
[undefined, value]
. - Converts a rejected promise to
[Error, undefined]
. - Rethrows non-Error rejections.
import { toResult, Result } from 'radashi'
const good = async (): Promise<number> => 1
const bad = async (): Promise<number> => {
throw new Error('bad')
}
const goodResult = await toResult(good())
// => [undefined, 1]
const badResult = await toResult(bad())
// => [Error('bad'), undefined]
Thanks to Alec Larson for their work on this feature!
Add memoLastCall
function β PR #353
The memoLastCall
function creates a memoized version of a function that caches only its most recent call. This is useful for optimizing expensive calculations when only the latest result needs to be cached, making it more memory-efficient than traditional memoization.
- Caches the last result of a function call.
- Returns the cached result if the function is called with the same arguments as the previous call.
- Optimizes expensive calculations by avoiding recalculation when the arguments are the same.
import * as _ from 'radashi'
const expensiveCalculation = (x: number, y: number): number => {
console.log('Calculating...')
return x + y
}
const memoizedCalc = _.memoLastCall(expensiveCalculation)
console.log(memoizedCalc(2, 3)) // Outputs: \"Calculating...\" then 5
console.log(memoizedCalc(2, 3)) // Outputs: 5 (uses cached result)
console.log(memoizedCalc(3, 4)) // Outputs: \"Calculating...\" then 7
console.log(memoizedCalc(2, 3)) // Outputs: \"Calculating...\" then 5 (previous cache was overwritten)
Thanks to Alec Larson for their work on this feature!
Add isAsyncIterable
function β PR #366
The isAsyncIterable
function checks if a value is an async iterable.
- Returns
true
for async iterables created by an async generator function. - Returns
true
for objects with a[Symbol.asyncIterator]
method. - Returns
false
for everything else.
import * as _ from 'radashi'
_.isAsyncIterable(
(async function* () {
yield 1
})(),
)
// => true
_.isAsyncIterable([1, 2, 3])
// => false
Thanks to Alec Larson for their work on this feature!
Add isBigInt
function β PR #369
The isBigInt
function returns true if the given value is a BigInt.
- Returns
true
whentypeof
returns'bigint'
. - Returns
false
for everything else.
import * as _ from 'radashi'
_.isBigInt(0n) // => true
_.isBigInt(BigInt(0)) // => true
_.isBigInt(12) // => false
_.isBigInt('0n') // => false
Thanks to Shan Shaji for their work on this feature!
New Features
BigInt support in isEmpty
β PR #374
The isEmpty
function now supports BigInt values.
- Returns
true
for0n
orBigInt(0)
.
import * as _ from 'radashi'
_.isEmpty(0n) // => true
_.isEmpty(BigInt(0)) // => true
_.isEmpty(1n) // => false
Thanks to Alec Larson for their work on this feature!
v12.3.4
Fixed
- (reduce) Align with native reduce behavior + perf improvements by @aleclarson in #341
v12.3.3
Types
- Let
map
callback return aPromiseLike
object by @aleclarson in #330
v12.3.2
v12.3.1
Fixed
- (parallel) Avoid range error with empty array by @aleclarson in #337
v12.3.0
New Functions
Add isClass
function β PR #239
The isClass
function determines if a value was declared using ES6 class
syntax, distinguishing modern class declarations from traditional constructor functions or other types.
- Only returns
true
for values created with theclass
keyword - Old-style constructor functions will return
false
- Built-in native class constructors (like
Error
) returnfalse
- Works with type narrowing for TypeScript
import * as _ from 'radashi'
class MyClass {
x = 1
}
function OldConstructor() {
this.x = 1
}
// Examples
_.isClass(MyClass) // true
_.isClass(OldConstructor) // false
_.isClass('string') // false
_.isClass(Error) // false
Thanks to Marlon Passos and Alec Larson for their work on this feature!
Β
Add isNullish
function β PR #277
The isNullish
function is a type-checking utility that determines whether a given value is either null
or undefined
. It helps you avoid the typos that an x == null
check is prone to, and it's shorter to write than x === undefined || x === null
.
import * as _ from 'radashi'
// Basic usage examples
_.isNullish(null) // true
_.isNullish(undefined) // true
_.isNullish('') // false
_.isNullish([]) // false
_.isNullish(0) // false
Thanks to Wei Xiaopeng for their work on this feature!
Β
Add cartesianProduct
function β PR #241
The cartesianProduct
function generates all possible combinations of elements from multiple input arrays, creating a new array containing every unique permutation of elements from those arrays.
- Works with any number of input arrays
- Returns an array of arrays representing all combinations
- Preserves the order of input arrays in the resulting combinations
- Can handle arrays of different types
import * as _ from 'radashi'
const colors = ['red', 'blue']
const numbers = [1, 2, 3]
const booleans = [true, false]
// Generate all combinations of colors, numbers, and booleans
const combinations = _.cartesianProduct(colors, numbers, booleans)
Thanks to Yam Borodetsky, Marlon Passos, and Alec Larson for their work on this feature!
Β
Add isUndefined
function β PR #305
The isUndefined
function is a type guard that checks whether a given value is specifically undefined
. It provides a simple and type-safe way to determine if a value has been left unassigned or is explicitly set to undefined
.
- Strictly checks for
undefined
using thetypeof
operator - Can be used for type narrowing in TypeScript
import * as _ from 'radashi'
// Basic usage examples
const result1 = _.isUndefined(undefined) // true
const result2 = _.isUndefined(null) // false
const result3 = _.isUndefined(42) // false
Thanks to RobinBobin for their work on this feature!
Β
Add timeout
function β PR #250
The timeout
function creates a promise that rejects after a specified delay, providing a way to set timeouts for asynchronous operations. It allows customizing the error message or type of error thrown when the timeout occurs.
- Can be used with a default
TimeoutError
or a custom error message/function - Primarily useful with
Promise.race
to add timeout functionality to async tasks
import * as _ from 'radashi'
// Basic usage: reject after 1 second with default TimeoutError
const basicTimeout = _.timeout(1000)
// With custom message
const customMessageTimeout = _.timeout(1000, 'Operation took too long')
// With Promise.race to limit async task duration
const someAsyncTask = async () => {
await _.sleep(5000) // Simulate a long-running task
return 'Task completed'
}
// Will reject after 1 second if task doesn't complete
const racedTask = await Promise.race([
someAsyncTask(),
_.timeout(1000, 'Task exceeded time limit'),
])
Thanks to Marlon Passos and Alec Larson for their work on this feature!
Β
Add dedent
function β PR #120
The dedent
function removes indentation from a multi-line string, making it easy to format and clean up text templates while preserving the relative indentation of embedded content.
- Supports both explicit and auto-detected indentation
- Works with tagged template strings
- Automatically handles multi-line embedded strings
- Removes the first leading and first trailing empty line
- Preserves relative indentation of content
import * as _ from 'radashi'
// Remove auto-detected indentation
const message = _.dedent`
Hello, world!
This is a dedented message.
`
// => 'Hello, world!\nThis is a dedented message.'
// Remove specific indentation
const customMessage = _.dedent('\n Hello\n World!\n\n', ' ')
// => ' Hello\n World!\n'
Thanks to Alec Larson for their work on this feature!
Β
New Features
Add signal
option to retry
β PR #262
The new feature introduces an optional signal
parameter to both the retry
function, allowing for manual interruption of async operations using AbortController
.
- The
signal
option accepts anAbortController.signal
- When the signal is aborted, no more calls to the callback will be made
- Aborting will throw a
DOMException
with the message "This operation was aborted" - Works consistently across Node.js and browser environments
import * as _ from 'radashi'
const abortController = new AbortController()
const signal = abortController.signal
const promise = _.retry(
{ times: 3, delay: 1000, signal },
async () => await fetchSomeData(),
)
// To abort the operation:
abortController.abort()
Thanks to ts-saidbe.abdiganiev and Alec Larson for their work on this feature!
Β
Add signal
option to parallel
β PR #262
The latest update adds an optional signal
option to the parallel
function, allowing you to interrupt parallel processing with an AbortController
.
- The
signal
option works with anAbortController.signal
- When aborted, it will throw a
DOMException
with an"AbortError"
name - Interruption only stops future iterations, not in-progress async calls
- Signals are compatible with both browser and Node.js environments
import * as _ from 'radashi'
// Abort a parallel operation
const abortController = new AbortController()
const signal = abortController.signal
const pizzas = await _.parallel(
{ limit: 2, signal },
['pepperoni', 'cheese', 'mushroom'],
async topping => {
return await bakePizzaInWoodFiredOven(topping)
},
)
// Abort the operation if needed
abortController.abort()
Thanks to ts-saidbe.abdiganiev and Alec Larson for their work on this feature!
Β
Tolerate out-of-range parallel
limit β PR #238
The parallel
function now automatically clamps the concurrency limit between 1 and the input array's length, ensuring more predictable and safe parallel processing.
- Previously, passing a limit larger than the array length or less than 1 could cause unexpected behavior
- The limit is now automatically adjusted to be within the valid range
import * as _ from 'radashi'
// Limit will be adjusted to 3 (array length)
const results = await _.parallel(
10,
['item1', 'item2', 'item3'],
async item => {
// Process each item
return item.toUpperCase()
},
)
Thanks to Marlon Passos and [Alec Larson](https://...
v12.2.3
Fixed
- (all) Be more lenient, reduce memory usage by @aleclarson in e6accd8
v12.2.2
Types
-
Export
PromiseWithResolvers
type by @aleclarson in #301 -
Improve
isEmpty
signature by @MarlonPassos-git in #219 -
Improve
draw
signature for non-empty arrays by @crishoj in #153