diff --git a/.size-limit.json b/.size-limit.json
index 3876dd09..c3acaeaa 100644
--- a/.size-limit.json
+++ b/.size-limit.json
@@ -2,42 +2,42 @@
{
"name": "es5-full",
"path": "lib/dist/es5/mod/ts-utils.js",
- "limit": "24.5 kb",
+ "limit": "27.5 kb",
"brotli": false,
"running": false
},
{
"name": "es6-full",
"path": "lib/dist/es6/mod/ts-utils.js",
- "limit": "23.5 kb",
+ "limit": "26.5 kb",
"brotli": false,
"running": false
},
{
"name": "es5-full-brotli",
"path": "lib/dist/es5/mod/ts-utils.js",
- "limit": "9 kb",
+ "limit": "10 kb",
"brotli": true,
"running": false
},
{
"name": "es6-full-brotli",
"path": "lib/dist/es6/mod/ts-utils.js",
- "limit": "9 kb",
+ "limit": "9.75 kb",
"brotli": true,
"running": false
},
{
"name": "es5-zip",
"path": "lib/dist/es5/mod/ts-utils.js",
- "limit": "9.5 Kb",
+ "limit": "11 Kb",
"gzip": true,
"running": false
},
{
"name": "es6-zip",
"path": "lib/dist/es6/mod/ts-utils.js",
- "limit": "9.5 Kb",
+ "limit": "10.5 Kb",
"gzip": true,
"running": false
},
@@ -68,7 +68,7 @@
{
"name": "es5-poly",
"path": "lib/bundle/es5/ts-polyfills-utils.js",
- "limit": "9 kb",
+ "limit": "10 kb",
"brotli": false,
"running": false
},
diff --git a/README.md b/README.md
index 8d7330d8..c6953ca8 100644
--- a/README.md
+++ b/README.md
@@ -108,12 +108,12 @@ Below is a categorized list of all available utilities with direct links to thei
| Type | Functions / Helpers / Aliases / Polyfills
|----------------------------|---------------------------------------------------
| Runtime Environment Checks | [getCancelIdleCallback](https://nevware21.github.io/ts-utils/typedoc/functions/getCancelIdleCallback.html)(); [getDocument](https://nevware21.github.io/ts-utils/typedoc/functions/getDocument.html)(); [getGlobal](https://nevware21.github.io/ts-utils/typedoc/functions/getGlobal.html)(); [getHistory](https://nevware21.github.io/ts-utils/typedoc/functions/getHistory.html)(); [getIdleCallback](https://nevware21.github.io/ts-utils/typedoc/functions/getIdleCallback.html)(); [getInst](https://nevware21.github.io/ts-utils/typedoc/functions/getInst.html)(); [getNavigator](https://nevware21.github.io/ts-utils/typedoc/functions/getNavigator.html)(); [getPerformance](https://nevware21.github.io/ts-utils/typedoc/functions/getPerformance.html)(); [getWindow](https://nevware21.github.io/ts-utils/typedoc/functions/getWindow.html)(); [hasDocument](https://nevware21.github.io/ts-utils/typedoc/functions/hasDocument.html)(); [hasHistory](https://nevware21.github.io/ts-utils/typedoc/functions/hasHistory.html)(); [hasNavigator](https://nevware21.github.io/ts-utils/typedoc/functions/hasNavigator.html)(); [hasPerformance](https://nevware21.github.io/ts-utils/typedoc/functions/hasPerformance.html)(); [hasWindow](https://nevware21.github.io/ts-utils/typedoc/functions/hasWindow.html)(); [isNode](https://nevware21.github.io/ts-utils/typedoc/functions/isNode.html)(); [isWebWorker](https://nevware21.github.io/ts-utils/typedoc/functions/isWebWorker.html)(); [hasIdleCallback](https://nevware21.github.io/ts-utils/typedoc/functions/hasIdleCallback.html)(); [lazySafeGetInst](https://nevware21.github.io/ts-utils/typedoc/functions/lazySafeGetInst.html)();
-| Type Identity | [isArray](https://nevware21.github.io/ts-utils/typedoc/functions/isArray.html)(); [isArrayBuffer](https://nevware21.github.io/ts-utils/typedoc/functions/isArrayBuffer.html)(); [isAsyncFunction](https://nevware21.github.io/ts-utils/typedoc/functions/isAsyncFunction.html)(); [isAsyncGenerator](https://nevware21.github.io/ts-utils/typedoc/functions/isAsyncGenerator.html)(); [isBigInt](https://nevware21.github.io/ts-utils/typedoc/functions/isBigInt.html)(); [isBlob](https://nevware21.github.io/ts-utils/typedoc/functions/isBlob.html)(); [isBoolean](https://nevware21.github.io/ts-utils/typedoc/functions/isBoolean.html)(); [isDate](https://nevware21.github.io/ts-utils/typedoc/functions/isDate.html)(); [isElement](https://nevware21.github.io/ts-utils/typedoc/functions/isElement.html)(); [isElementLike](https://nevware21.github.io/ts-utils/typedoc/functions/isElementLike.html)(); [isError](https://nevware21.github.io/ts-utils/typedoc/functions/isError.html)(); [isFile](https://nevware21.github.io/ts-utils/typedoc/functions/isFile.html)(); [isFiniteNumber](https://nevware21.github.io/ts-utils/typedoc/functions/isFiniteNumber.html)(); [isFormData](https://nevware21.github.io/ts-utils/typedoc/functions/isFormData.html)(); [isFunction](https://nevware21.github.io/ts-utils/typedoc/functions/isFunction.html)(); [isGenerator](https://nevware21.github.io/ts-utils/typedoc/functions/isGenerator.html)(); [isInteger](https://nevware21.github.io/ts-utils/typedoc/functions/isInteger.html)(); [isIterable](https://nevware21.github.io/ts-utils/typedoc/functions/isIterable.html)(); [isIterator](https://nevware21.github.io/ts-utils/typedoc/functions/isIterator.html)(); [isMap](https://nevware21.github.io/ts-utils/typedoc/functions/isMap.html)(); [isMapLike](https://nevware21.github.io/ts-utils/typedoc/functions/isMapLike.html)(); [isNullOrUndefined](https://nevware21.github.io/ts-utils/typedoc/functions/isNullOrUndefined.html)(); [isNumber](https://nevware21.github.io/ts-utils/typedoc/functions/isNumber.html)(); [isObject](https://nevware21.github.io/ts-utils/typedoc/functions/isObject.html)(); [isPlainObject](https://nevware21.github.io/ts-utils/typedoc/functions/isPlainObject.html)(); [isPrimitive](https://nevware21.github.io/ts-utils/typedoc/functions/isPrimitive.html)(); [isPrimitiveType](https://nevware21.github.io/ts-utils/typedoc/functions/isPrimitiveType.html)(); [isPromise](https://nevware21.github.io/ts-utils/typedoc/functions/isPromise.html)(); [isPromiseLike](https://nevware21.github.io/ts-utils/typedoc/functions/isPromiseLike.html)(); [isRegExp](https://nevware21.github.io/ts-utils/typedoc/functions/isRegExp.html)(); [isSet](https://nevware21.github.io/ts-utils/typedoc/functions/isSet.html)(); [isSetLike](https://nevware21.github.io/ts-utils/typedoc/functions/isSetLike.html)(); [isStrictNullOrUndefined](https://nevware21.github.io/ts-utils/typedoc/functions/isStrictNullOrUndefined.html)(); [isStrictUndefined](https://nevware21.github.io/ts-utils/typedoc/functions/isStrictUndefined.html)(); [isString](https://nevware21.github.io/ts-utils/typedoc/functions/isString.html)(); [isThenable](https://nevware21.github.io/ts-utils/typedoc/functions/isThenable.html)(); [isTypeof](https://nevware21.github.io/ts-utils/typedoc/functions/isTypeof.html)(); [isUndefined](https://nevware21.github.io/ts-utils/typedoc/functions/isUndefined.html)(); [isWeakMap](https://nevware21.github.io/ts-utils/typedoc/functions/isWeakMap.html)(); [isWeakSet](https://nevware21.github.io/ts-utils/typedoc/functions/isWeakSet.html)();
+| Type Identity | [isArray](https://nevware21.github.io/ts-utils/typedoc/functions/isArray.html)(); [isArrayLike](https://nevware21.github.io/ts-utils/typedoc/functions/isArrayLike.html)(); [isArrayBuffer](https://nevware21.github.io/ts-utils/typedoc/functions/isArrayBuffer.html)(); [isAsyncFunction](https://nevware21.github.io/ts-utils/typedoc/functions/isAsyncFunction.html)(); [isAsyncGenerator](https://nevware21.github.io/ts-utils/typedoc/functions/isAsyncGenerator.html)(); [isBigInt](https://nevware21.github.io/ts-utils/typedoc/functions/isBigInt.html)(); [isBlob](https://nevware21.github.io/ts-utils/typedoc/functions/isBlob.html)(); [isBoolean](https://nevware21.github.io/ts-utils/typedoc/functions/isBoolean.html)(); [isDate](https://nevware21.github.io/ts-utils/typedoc/functions/isDate.html)(); [isElement](https://nevware21.github.io/ts-utils/typedoc/functions/isElement.html)(); [isElementLike](https://nevware21.github.io/ts-utils/typedoc/functions/isElementLike.html)(); [isError](https://nevware21.github.io/ts-utils/typedoc/functions/isError.html)(); [isFile](https://nevware21.github.io/ts-utils/typedoc/functions/isFile.html)(); [isFiniteNumber](https://nevware21.github.io/ts-utils/typedoc/functions/isFiniteNumber.html)(); [isFormData](https://nevware21.github.io/ts-utils/typedoc/functions/isFormData.html)(); [isFunction](https://nevware21.github.io/ts-utils/typedoc/functions/isFunction.html)(); [isGenerator](https://nevware21.github.io/ts-utils/typedoc/functions/isGenerator.html)(); [isInteger](https://nevware21.github.io/ts-utils/typedoc/functions/isInteger.html)(); [isIterable](https://nevware21.github.io/ts-utils/typedoc/functions/isIterable.html)(); [isIterator](https://nevware21.github.io/ts-utils/typedoc/functions/isIterator.html)(); [isMap](https://nevware21.github.io/ts-utils/typedoc/functions/isMap.html)(); [isMapLike](https://nevware21.github.io/ts-utils/typedoc/functions/isMapLike.html)(); [isNullOrUndefined](https://nevware21.github.io/ts-utils/typedoc/functions/isNullOrUndefined.html)(); [isNumber](https://nevware21.github.io/ts-utils/typedoc/functions/isNumber.html)(); [isObject](https://nevware21.github.io/ts-utils/typedoc/functions/isObject.html)(); [isPlainObject](https://nevware21.github.io/ts-utils/typedoc/functions/isPlainObject.html)(); [isPrimitive](https://nevware21.github.io/ts-utils/typedoc/functions/isPrimitive.html)(); [isPrimitiveType](https://nevware21.github.io/ts-utils/typedoc/functions/isPrimitiveType.html)(); [isPromise](https://nevware21.github.io/ts-utils/typedoc/functions/isPromise.html)(); [isPromiseLike](https://nevware21.github.io/ts-utils/typedoc/functions/isPromiseLike.html)(); [isRegExp](https://nevware21.github.io/ts-utils/typedoc/functions/isRegExp.html)(); [isSet](https://nevware21.github.io/ts-utils/typedoc/functions/isSet.html)(); [isSetLike](https://nevware21.github.io/ts-utils/typedoc/functions/isSetLike.html)(); [isStrictNullOrUndefined](https://nevware21.github.io/ts-utils/typedoc/functions/isStrictNullOrUndefined.html)(); [isStrictUndefined](https://nevware21.github.io/ts-utils/typedoc/functions/isStrictUndefined.html)(); [isString](https://nevware21.github.io/ts-utils/typedoc/functions/isString.html)(); [isThenable](https://nevware21.github.io/ts-utils/typedoc/functions/isThenable.html)(); [isTypeof](https://nevware21.github.io/ts-utils/typedoc/functions/isTypeof.html)(); [isUndefined](https://nevware21.github.io/ts-utils/typedoc/functions/isUndefined.html)(); [isWeakMap](https://nevware21.github.io/ts-utils/typedoc/functions/isWeakMap.html)(); [isWeakSet](https://nevware21.github.io/ts-utils/typedoc/functions/isWeakSet.html)();
| Value Check | [hasValue](https://nevware21.github.io/ts-utils/typedoc/functions/hasValue.html)(); [isDefined](https://nevware21.github.io/ts-utils/typedoc/functions/isDefined.html)(); [isEmpty](https://nevware21.github.io/ts-utils/typedoc/functions/isEmpty.html)(); [isNotTruthy](https://nevware21.github.io/ts-utils/typedoc/functions/isNotTruthy.html)(); [isNullOrUndefined](https://nevware21.github.io/ts-utils/typedoc/functions/isNullOrUndefined.html)(); [isStrictNullOrUndefined](https://nevware21.github.io/ts-utils/typedoc/functions/isStrictNullOrUndefined.html)(); [isStrictUndefined](https://nevware21.github.io/ts-utils/typedoc/functions/isStrictUndefined.html)(); [isTruthy](https://nevware21.github.io/ts-utils/typedoc/functions/isTruthy.html)(); [isUndefined](https://nevware21.github.io/ts-utils/typedoc/functions/isUndefined.html)();
| Value | [getValueByKey](https://nevware21.github.io/ts-utils/typedoc/functions/getValueByKey.html)(); [setValueByKey](https://nevware21.github.io/ts-utils/typedoc/functions/setValueByKey.html)(); [getValueByIter](https://nevware21.github.io/ts-utils/typedoc/functions/getValueByIter.html)(); [setValueByIter](https://nevware21.github.io/ts-utils/typedoc/functions/setValueByIter.html)(); [encodeAsJson](https://nevware21.github.io/ts-utils/typedoc/functions/encodeAsJson.html)(); [encodeAsHtml](https://nevware21.github.io/ts-utils/typedoc/functions/encodeAsHtml.html)(); [asString](https://nevware21.github.io/ts-utils/typedoc/functions/asString.html)(); [getIntValue](https://nevware21.github.io/ts-utils/typedoc/functions/getIntValue.html)(); [normalizeJsName](https://nevware21.github.io/ts-utils/typedoc/functions/normalizeJsName.html)();
| |
-| Array | [arrAppend](https://nevware21.github.io/ts-utils/typedoc/functions/arrAppend.html)(); [arrContains](https://nevware21.github.io/ts-utils/typedoc/functions/arrContains.html)(); [arrEvery](https://nevware21.github.io/ts-utils/typedoc/functions/arrEvery.html)(); [arrFilter](https://nevware21.github.io/ts-utils/typedoc/functions/arrFilter.html)(); [arrFind](https://nevware21.github.io/ts-utils/typedoc/functions/arrFind.html)(); [arrFindIndex](https://nevware21.github.io/ts-utils/typedoc/functions/arrFindIndex.html)(); [arrFindLast](https://nevware21.github.io/ts-utils/typedoc/functions/arrFindLast.html)(); [arrFindLastIndex](https://nevware21.github.io/ts-utils/typedoc/functions/arrFindLastIndex.html)(); [arrForEach](https://nevware21.github.io/ts-utils/typedoc/functions/arrForEach.html)(); [arrFrom](https://nevware21.github.io/ts-utils/typedoc/functions/arrFrom.html)(); [arrIncludes](https://nevware21.github.io/ts-utils/typedoc/functions/arrIncludes.html)(); [arrIndexOf](https://nevware21.github.io/ts-utils/typedoc/functions/arrIndexOf.html)(); [arrLastIndexOf](https://nevware21.github.io/ts-utils/typedoc/functions/arrLastIndexOf.html)(); [arrMap](https://nevware21.github.io/ts-utils/typedoc/functions/arrMap.html)(); [arrReduce](https://nevware21.github.io/ts-utils/typedoc/functions/arrReduce.html)(); [arrSlice](https://nevware21.github.io/ts-utils/typedoc/functions/arrSlice.html)(); [arrSome](https://nevware21.github.io/ts-utils/typedoc/functions/arrSome.html)(); [getLength](https://nevware21.github.io/ts-utils/typedoc/functions/getLength.html)(); [isArray](https://nevware21.github.io/ts-utils/typedoc/functions/isArray.html)();
[polyIsArray](https://nevware21.github.io/ts-utils/typedoc/functions/polyIsArray.html)(); [polyArrIncludes](https://nevware21.github.io/ts-utils/typedoc/functions/polyArrIncludes.html)(); [polyArrFind](https://nevware21.github.io/ts-utils/typedoc/functions/polyArrFind.html)(); [polyArrFindIndex](https://nevware21.github.io/ts-utils/typedoc/functions/polyArrFindIndex.html)(); [polyArrFindLastIndex](https://nevware21.github.io/ts-utils/typedoc/functions/polyArrFindLastIndex.html)(); [polyArrFindLast](https://nevware21.github.io/ts-utils/typedoc/functions/polyArrFindLast.html)(); [polyArrFindLastIndex](https://nevware21.github.io/ts-utils/typedoc/functions/polyArrFindLastIndex.html)(); [polyArrFrom](https://nevware21.github.io/ts-utils/typedoc/functions/polyArrFrom.html)();
-| ArrayLike | [arrContains](https://nevware21.github.io/ts-utils/typedoc/functions/arrContains.html)(); [arrEvery](https://nevware21.github.io/ts-utils/typedoc/functions/arrEvery.html)(); [arrFilter](https://nevware21.github.io/ts-utils/typedoc/functions/arrFilter.html)(); [arrFind](https://nevware21.github.io/ts-utils/typedoc/functions/arrFind.html)(); [arrFindIndex](https://nevware21.github.io/ts-utils/typedoc/functions/arrFindIndex.html)(); [arrFindLast](https://nevware21.github.io/ts-utils/typedoc/functions/arrFindLast.html)(); [arrFindLastIndex](https://nevware21.github.io/ts-utils/typedoc/functions/arrFindLastIndex.html)(); [arrForEach](https://nevware21.github.io/ts-utils/typedoc/functions/arrForEach.html)(); [arrFrom](https://nevware21.github.io/ts-utils/typedoc/functions/arrFrom.html)(); [arrIncludes](https://nevware21.github.io/ts-utils/typedoc/functions/arrIncludes.html)(); [arrIndexOf](https://nevware21.github.io/ts-utils/typedoc/functions/arrIndexOf.html)(); [arrLastIndexOf](https://nevware21.github.io/ts-utils/typedoc/functions/arrLastIndexOf.html)(); [arrMap](https://nevware21.github.io/ts-utils/typedoc/functions/arrMap.html)(); [arrReduce](https://nevware21.github.io/ts-utils/typedoc/functions/arrReduce.html)(); [arrSlice](https://nevware21.github.io/ts-utils/typedoc/functions/arrSlice.html)(); [arrSome](https://nevware21.github.io/ts-utils/typedoc/functions/arrSome.html)(); [getLength](https://nevware21.github.io/ts-utils/typedoc/functions/getLength.html)(); [objEntries](https://nevware21.github.io/ts-utils/typedoc/functions/objEntries.html)(); [objValues](https://nevware21.github.io/ts-utils/typedoc/functions/objValues.html)();
+| Array | [arrAppend](https://nevware21.github.io/ts-utils/typedoc/functions/arrAppend.html)(); [arrAt](https://nevware21.github.io/ts-utils/typedoc/functions/arrAt.html)(); [arrChunk](https://nevware21.github.io/ts-utils/typedoc/functions/arrChunk.html)(); [arrCompact](https://nevware21.github.io/ts-utils/typedoc/functions/arrCompact.html)(); [arrContains](https://nevware21.github.io/ts-utils/typedoc/functions/arrContains.html)(); [arrDifference](https://nevware21.github.io/ts-utils/typedoc/functions/arrDifference.html)(); [arrDrop](https://nevware21.github.io/ts-utils/typedoc/functions/arrDrop.html)(); [arrDropWhile](https://nevware21.github.io/ts-utils/typedoc/functions/arrDropWhile.html)(); [arrEvery](https://nevware21.github.io/ts-utils/typedoc/functions/arrEvery.html)(); [arrFilter](https://nevware21.github.io/ts-utils/typedoc/functions/arrFilter.html)(); [arrFill](https://nevware21.github.io/ts-utils/typedoc/functions/arrFill.html)(); [arrFind](https://nevware21.github.io/ts-utils/typedoc/functions/arrFind.html)(); [arrFindIndex](https://nevware21.github.io/ts-utils/typedoc/functions/arrFindIndex.html)(); [arrFindLast](https://nevware21.github.io/ts-utils/typedoc/functions/arrFindLast.html)(); [arrFindLastIndex](https://nevware21.github.io/ts-utils/typedoc/functions/arrFindLastIndex.html)(); [arrFlatten](https://nevware21.github.io/ts-utils/typedoc/functions/arrFlatten.html)(); [arrForEach](https://nevware21.github.io/ts-utils/typedoc/functions/arrForEach.html)(); [arrFrom](https://nevware21.github.io/ts-utils/typedoc/functions/arrFrom.html)(); [arrGroupBy](https://nevware21.github.io/ts-utils/typedoc/functions/arrGroupBy.html)(); [arrIncludes](https://nevware21.github.io/ts-utils/typedoc/functions/arrIncludes.html)(); [arrIndexOf](https://nevware21.github.io/ts-utils/typedoc/functions/arrIndexOf.html)(); [arrIntersection](https://nevware21.github.io/ts-utils/typedoc/functions/arrIntersection.html)(); [arrLastIndexOf](https://nevware21.github.io/ts-utils/typedoc/functions/arrLastIndexOf.html)(); [arrMap](https://nevware21.github.io/ts-utils/typedoc/functions/arrMap.html)(); [arrPartition](https://nevware21.github.io/ts-utils/typedoc/functions/arrPartition.html)(); [arrReduce](https://nevware21.github.io/ts-utils/typedoc/functions/arrReduce.html)(); [arrReverse](https://nevware21.github.io/ts-utils/typedoc/functions/arrReverse.html)(); [arrRotate](https://nevware21.github.io/ts-utils/typedoc/functions/arrRotate.html)(); [arrSample](https://nevware21.github.io/ts-utils/typedoc/functions/arrSample.html)(); [arrShuffle](https://nevware21.github.io/ts-utils/typedoc/functions/arrShuffle.html)(); [arrSlice](https://nevware21.github.io/ts-utils/typedoc/functions/arrSlice.html)(); [arrSome](https://nevware21.github.io/ts-utils/typedoc/functions/arrSome.html)(); [arrTake](https://nevware21.github.io/ts-utils/typedoc/functions/arrTake.html)(); [arrTakeWhile](https://nevware21.github.io/ts-utils/typedoc/functions/arrTakeWhile.html)(); [arrUnion](https://nevware21.github.io/ts-utils/typedoc/functions/arrUnion.html)(); [arrUnique](https://nevware21.github.io/ts-utils/typedoc/functions/arrUnique.html)(); [arrUnzip](https://nevware21.github.io/ts-utils/typedoc/functions/arrUnzip.html)(); [arrWith](https://nevware21.github.io/ts-utils/typedoc/functions/arrWith.html)(); [arrZip](https://nevware21.github.io/ts-utils/typedoc/functions/arrZip.html)(); [getLength](https://nevware21.github.io/ts-utils/typedoc/functions/getLength.html)(); [isArray](https://nevware21.github.io/ts-utils/typedoc/functions/isArray.html)();
[polyIsArray](https://nevware21.github.io/ts-utils/typedoc/functions/polyIsArray.html)(); [polyArrIncludes](https://nevware21.github.io/ts-utils/typedoc/functions/polyArrIncludes.html)(); [polyArrFind](https://nevware21.github.io/ts-utils/typedoc/functions/polyArrFind.html)(); [polyArrFindIndex](https://nevware21.github.io/ts-utils/typedoc/functions/polyArrFindIndex.html)(); [polyArrFindLast](https://nevware21.github.io/ts-utils/typedoc/functions/polyArrFindLast.html)(); [polyArrFindLastIndex](https://nevware21.github.io/ts-utils/typedoc/functions/polyArrFindLastIndex.html)(); [polyArrFrom](https://nevware21.github.io/ts-utils/typedoc/functions/polyArrFrom.html)();
+| ArrayLike | [arrAt](https://nevware21.github.io/ts-utils/typedoc/functions/arrAt.html)(); [arrChunk](https://nevware21.github.io/ts-utils/typedoc/functions/arrChunk.html)(); [arrCompact](https://nevware21.github.io/ts-utils/typedoc/functions/arrCompact.html)(); [arrContains](https://nevware21.github.io/ts-utils/typedoc/functions/arrContains.html)(); [arrDifference](https://nevware21.github.io/ts-utils/typedoc/functions/arrDifference.html)(); [arrDrop](https://nevware21.github.io/ts-utils/typedoc/functions/arrDrop.html)(); [arrDropWhile](https://nevware21.github.io/ts-utils/typedoc/functions/arrDropWhile.html)(); [arrEvery](https://nevware21.github.io/ts-utils/typedoc/functions/arrEvery.html)(); [arrFilter](https://nevware21.github.io/ts-utils/typedoc/functions/arrFilter.html)(); [arrFill](https://nevware21.github.io/ts-utils/typedoc/functions/arrFill.html)(); [arrFind](https://nevware21.github.io/ts-utils/typedoc/functions/arrFind.html)(); [arrFindIndex](https://nevware21.github.io/ts-utils/typedoc/functions/arrFindIndex.html)(); [arrFindLast](https://nevware21.github.io/ts-utils/typedoc/functions/arrFindLast.html)(); [arrFindLastIndex](https://nevware21.github.io/ts-utils/typedoc/functions/arrFindLastIndex.html)(); [arrFlatten](https://nevware21.github.io/ts-utils/typedoc/functions/arrFlatten.html)(); [arrForEach](https://nevware21.github.io/ts-utils/typedoc/functions/arrForEach.html)(); [arrFrom](https://nevware21.github.io/ts-utils/typedoc/functions/arrFrom.html)(); [arrGroupBy](https://nevware21.github.io/ts-utils/typedoc/functions/arrGroupBy.html)(); [arrIncludes](https://nevware21.github.io/ts-utils/typedoc/functions/arrIncludes.html)(); [arrIndexOf](https://nevware21.github.io/ts-utils/typedoc/functions/arrIndexOf.html)(); [arrIntersection](https://nevware21.github.io/ts-utils/typedoc/functions/arrIntersection.html)(); [arrLastIndexOf](https://nevware21.github.io/ts-utils/typedoc/functions/arrLastIndexOf.html)(); [arrMap](https://nevware21.github.io/ts-utils/typedoc/functions/arrMap.html)(); [arrPartition](https://nevware21.github.io/ts-utils/typedoc/functions/arrPartition.html)(); [arrReduce](https://nevware21.github.io/ts-utils/typedoc/functions/arrReduce.html)(); [arrReverse](https://nevware21.github.io/ts-utils/typedoc/functions/arrReverse.html)(); [arrRotate](https://nevware21.github.io/ts-utils/typedoc/functions/arrRotate.html)(); [arrSample](https://nevware21.github.io/ts-utils/typedoc/functions/arrSample.html)(); [arrShuffle](https://nevware21.github.io/ts-utils/typedoc/functions/arrShuffle.html)(); [arrSlice](https://nevware21.github.io/ts-utils/typedoc/functions/arrSlice.html)(); [arrSome](https://nevware21.github.io/ts-utils/typedoc/functions/arrSome.html)(); [arrTake](https://nevware21.github.io/ts-utils/typedoc/functions/arrTake.html)(); [arrTakeWhile](https://nevware21.github.io/ts-utils/typedoc/functions/arrTakeWhile.html)(); [arrUnion](https://nevware21.github.io/ts-utils/typedoc/functions/arrUnion.html)(); [arrUnique](https://nevware21.github.io/ts-utils/typedoc/functions/arrUnique.html)(); [arrUnzip](https://nevware21.github.io/ts-utils/typedoc/functions/arrUnzip.html)(); [arrWith](https://nevware21.github.io/ts-utils/typedoc/functions/arrWith.html)(); [arrZip](https://nevware21.github.io/ts-utils/typedoc/functions/arrZip.html)(); [getLength](https://nevware21.github.io/ts-utils/typedoc/functions/getLength.html)(); [objEntries](https://nevware21.github.io/ts-utils/typedoc/functions/objEntries.html)(); [objValues](https://nevware21.github.io/ts-utils/typedoc/functions/objValues.html)();
| DOM | [isElement](https://nevware21.github.io/ts-utils/typedoc/functions/isElement.html)(); [isElementLike](https://nevware21.github.io/ts-utils/typedoc/functions/isElementLike.html)();
| Enum | [createEnum](https://nevware21.github.io/ts-utils/typedoc/functions/createEnum.html)(); [createEnumKeyMap](https://nevware21.github.io/ts-utils/typedoc/functions/createEnumKeyMap.html)(); [createEnumValueMap](https://nevware21.github.io/ts-utils/typedoc/functions/createEnumValueMap.html)(); [createSimpleMap](https://nevware21.github.io/ts-utils/typedoc/functions/createSimpleMap.html)(); [createTypeMap](https://nevware21.github.io/ts-utils/typedoc/functions/createTypeMap.html)();
| Error | [createCustomError](https://nevware21.github.io/ts-utils/typedoc/functions/createCustomError.html)(); [isError](https://nevware21.github.io/ts-utils/typedoc/functions/isError.html)(); [throwError](https://nevware21.github.io/ts-utils/typedoc/functions/throwError.html)(); [throwRangeError](https://nevware21.github.io/ts-utils/typedoc/functions/throwRangeError.html)(); [throwTypeError](https://nevware21.github.io/ts-utils/typedoc/functions/throwTypeError.html)(); [throwUnsupported](https://nevware21.github.io/ts-utils/typedoc/functions/throwUnsupported.html)();
diff --git a/lib/src/array/at.ts b/lib/src/array/at.ts
new file mode 100644
index 00000000..297e448e
--- /dev/null
+++ b/lib/src/array/at.ts
@@ -0,0 +1,71 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { ArrProto } from "../internal/constants";
+import { _unwrapFunctionWithPoly } from "../internal/unwrapFunction";
+import { isArrayLike } from "../helpers/base";
+
+/**
+ * The arrAt() method takes an integer value and returns the item at that index, allowing for
+ * positive and negative integers. Negative integers count back from the last item in the array.
+ * This is an ES2022 feature with polyfill support for older environments.
+ * @function
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the type of array elements
+ * @param theArray - The array or array-like object to get element from
+ * @param index - The index of the element to return. Negative index counts from the end
+ * @returns The element at the specified index, or undefined if index is out of range
+ * @example
+ * ```ts
+ * arrAt([1, 2, 3, 4, 5], 0); // 1
+ * arrAt([1, 2, 3, 4, 5], 2); // 3
+ * arrAt([1, 2, 3, 4, 5], -1); // 5
+ * arrAt([1, 2, 3, 4, 5], -2); // 4
+ * arrAt([1, 2, 3], 10); // undefined
+ * arrAt([1, 2, 3], -10); // undefined
+ *
+ * // Array-like objects
+ * arrAt({ length: 3, 0: "a", 1: "b", 2: "c" }, -1); // "c"
+ * ```
+ */
+export const arrAt = (/*#__PURE__*/_unwrapFunctionWithPoly("at", ArrProto as any, polyArrAt) as (theArray: ArrayLike, index: number) => T | undefined);
+
+/**
+ * Polyfill implementation of Array.at() for environments that don't support it.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @group Polyfill
+ * @typeParam T - Identifies the type of array elements
+ * @param theArray - The array or array-like object to get element from
+ * @param index - The index of the element to return
+ * @returns The element at the specified index, or undefined if out of range
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function polyArrAt(theArray: ArrayLike, index: number): T | undefined {
+ let result: T | undefined;
+
+ if (isArrayLike(theArray)) {
+ const len = theArray.length;
+ let idx = index;
+
+ // Convert negative index to positive
+ if (idx < 0) {
+ idx = len + idx;
+ }
+
+ // Check bounds and get value
+ if (idx >= 0 && idx < len) {
+ result = theArray[idx];
+ }
+ }
+
+ return result;
+}
diff --git a/lib/src/array/callbacks.ts b/lib/src/array/callbacks.ts
index 9845cc26..a34c9e0d 100644
--- a/lib/src/array/callbacks.ts
+++ b/lib/src/array/callbacks.ts
@@ -14,8 +14,8 @@
* @group ArrayLike
* @typeParam T - Identifies the type of array elements
* @typeParam E - Identifies the type of the return array elements (defaults to T)
- * @param value - The cuirrent element of the array being processed.
- * @param index - The index of the current elemety of the array being processed.
+ * @param value - The current element of the array being processed.
+ * @param index - The index of the current element of the array being processed.
* @param array - The array being processed.
* @returns A boolean value indicating that the value is of the type expected (the test is true)
*/
@@ -29,8 +29,8 @@ export type ArrPredicateCallbackFn = (value: T, index: number, a
* @group ArrayLike
* @typeParam T - Identifies the type of array elements
* @typeParam E - Identifies the type of the return array elements (defaults to T)
- * @param value - The cuirrent element of the array being processed.
- * @param index - The index of the current elemety of the array being processed.
+ * @param value - The current element of the array being processed.
+ * @param index - The index of the current element of the array being processed.
* @param array - The array being processed.
*/
export type ArrPredicateCallbackFn2 = (value: T, index: number, array: T[]) => unknown;
diff --git a/lib/src/array/chunk.ts b/lib/src/array/chunk.ts
new file mode 100644
index 00000000..19aa3624
--- /dev/null
+++ b/lib/src/array/chunk.ts
@@ -0,0 +1,56 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { isArrayLike } from "../helpers/base";
+import { arrForEach } from "./forEach";
+
+/**
+ * The arrChunk() method returns a new array with elements divided into groups of a specified size.
+ * The last group may have fewer elements if the array length is not divisible by the chunk size.
+ * @function
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @param theArray - The array or array-like object to chunk
+ * @param size - The size of each chunk. Must be a positive integer
+ * @returns A new array of chunks, where each chunk is an array of the specified size
+ * @example
+ * ```ts
+ * arrChunk([1, 2, 3, 4, 5, 6, 7], 2); // [[1, 2], [3, 4], [5, 6], [7]]
+ * arrChunk([1, 2, 3, 4, 5], 3); // [[1, 2, 3], [4, 5]]
+ * arrChunk([1, 2, 3], 1); // [[1], [2], [3]]
+ * arrChunk([1, 2, 3], 5); // [[1, 2, 3]]
+ * arrChunk([], 2); // []
+ *
+ * // Array-like objects
+ * arrChunk({ length: 5, 0: "a", 1: "b", 2: "c", 3: "d", 4: "e" }, 2);
+ * // [["a", "b"], ["c", "d"], ["e"]]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrChunk(theArray: ArrayLike | null | undefined, size: number): T[][] {
+ const result: T[][] = [];
+
+ if (isArrayLike(theArray) && size > 0) {
+ let idx = 0;
+ let chunkIdx = -1;
+
+ arrForEach(theArray, (item) => {
+ if (idx % size === 0) {
+ result.push([]);
+ chunkIdx++;
+ }
+
+ result[chunkIdx].push(item);
+ idx++;
+ });
+ }
+
+ return result;
+}
diff --git a/lib/src/array/compact.ts b/lib/src/array/compact.ts
new file mode 100644
index 00000000..a097b48b
--- /dev/null
+++ b/lib/src/array/compact.ts
@@ -0,0 +1,46 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { isArrayLike } from "../helpers/base";
+import { arrForEach } from "./forEach";
+
+/**
+ * The arrCompact() method returns a new array with all falsy values removed.
+ * Falsy values include: false, 0, -0, 0n, "", null, undefined, and NaN.
+ * @function
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @param theArray - The array or array-like object to compact
+ * @returns A new array with all falsy values filtered out
+ * @example
+ * ```ts
+ * arrCompact([0, 1, false, 2, "", 3, null, undefined, 4]); // [1, 2, 3, 4]
+ * arrCompact([false, 0, "", null, undefined]); // []
+ * arrCompact([1, 2, 3]); // [1, 2, 3]
+ * arrCompact([]); // []
+ *
+ * // Array-like objects
+ * arrCompact({ length: 5, 0: 0, 1: 1, 2: false, 3: 2, 4: null }); // [1, 2]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrCompact(theArray: ArrayLike | null | undefined): T[] {
+ const result: T[] = [];
+
+ if (isArrayLike(theArray)) {
+ arrForEach(theArray, (item) => {
+ if (item) {
+ result.push(item);
+ }
+ });
+ }
+
+ return result;
+}
diff --git a/lib/src/array/difference.ts b/lib/src/array/difference.ts
new file mode 100644
index 00000000..9d702503
--- /dev/null
+++ b/lib/src/array/difference.ts
@@ -0,0 +1,58 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { isArrayLike } from "../helpers/base";
+import { arrForEach } from "./forEach";
+import { arrIncludes } from "./includes";
+
+/**
+ * The arrDifference() method returns a new array containing elements from the first array
+ * that do not exist in any of the other provided arrays. Uses strict equality (===) for comparison.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @param theArray - The source array to compare from
+ * @param excludeArrays - One or more arrays whose values should be excluded
+ * @returns A new array containing elements only in the source array
+ * @example
+ * ```ts
+ * arrDifference([1, 2, 3, 4], [2, 4]); // [1, 3]
+ * arrDifference([1, 2, 3], [2], [3]); // [1]
+ * arrDifference(["a", "b", "c"], ["b"]); // ["a", "c"]
+ * arrDifference([1, 2, 3], []); // [1, 2, 3]
+ * arrDifference([], [1, 2]); // []
+ *
+ * // Array-like objects
+ * arrDifference({ length: 3, 0: 1, 1: 2, 2: 3 }, [2]); // [1, 3]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrDifference(theArray: ArrayLike | null | undefined, ...excludeArrays: ArrayLike[]): T[] {
+ let result: T[] = [];
+
+ if (isArrayLike(theArray)) {
+ arrForEach(theArray, (item) => {
+ let excluded = false;
+ for (let lp = 0; lp < excludeArrays.length; lp++) {
+ let exclValue = excludeArrays[lp];
+ // Check if excludeArray is valid before using arrIncludes
+ if (isArrayLike(exclValue) && arrIncludes(exclValue, item)) {
+ excluded = true;
+ break;
+ }
+ }
+
+ if (!excluded) {
+ result.push(item);
+ }
+ });
+ }
+
+ return result;
+}
diff --git a/lib/src/array/drop.ts b/lib/src/array/drop.ts
new file mode 100644
index 00000000..ecd7f1c3
--- /dev/null
+++ b/lib/src/array/drop.ts
@@ -0,0 +1,37 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { arrSlice } from "./slice";
+import { mathMax } from "../math/min_max";
+
+/**
+ * The arrDrop() method returns a new array with the first n elements removed from the source array.
+ * If n is greater than the array length, returns empty array. If n is negative or 0, returns all elements.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @param theArray - The array or array-like object to drop from
+ * @param count - The number of elements to drop from the beginning
+ * @returns A new array with the first n elements removed
+ * @example
+ * ```ts
+ * arrDrop([1, 2, 3, 4, 5], 2); // [3, 4, 5]
+ * arrDrop(["a", "b", "c"], 1); // ["b", "c"]
+ * arrDrop([1, 2], 5); // []
+ * arrDrop([1, 2, 3], 0); // [1, 2, 3]
+ * arrDrop([1, 2, 3], -1); // [1, 2, 3]
+ *
+ * // Array-like objects
+ * arrDrop({ length: 4, 0: 1, 1: 2, 2: 3, 3: 4 }, 2); // [3, 4]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrDrop(theArray: ArrayLike | null | undefined, count: number): T[] {
+ return arrSlice(theArray, mathMax(0, count));
+}
diff --git a/lib/src/array/drop_while.ts b/lib/src/array/drop_while.ts
new file mode 100644
index 00000000..8155e3b7
--- /dev/null
+++ b/lib/src/array/drop_while.ts
@@ -0,0 +1,58 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { fnCall } from "../funcs/funcs";
+import { isArrayLike } from "../helpers/base";
+import { getLength } from "../helpers/length";
+import { ArrPredicateCallbackFn, ArrPredicateCallbackFn2 } from "./callbacks";
+import { arrForEach } from "./forEach";
+import { arrSlice } from "./slice";
+
+/**
+ * The arrDropWhile() method returns a new array with elements from the beginning removed
+ * as long as the predicate function returns true. Once the predicate returns false,
+ * all remaining elements (including that one) are included in the result.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @typeParam E - Identifies the narrowed type when using type guards
+ * @param theArray - The array or array-like object to drop from
+ * @param callbackFn - Function to test each element. Return true to drop, false to stop dropping
+ * @param thisArg - Optional value to use as `this` when executing callbackFn
+ * @returns A new array with leading elements removed while predicate was true
+ * @example
+ * ```ts
+ * arrDropWhile([1, 2, 3, 4, 1], x => x < 3); // [3, 4, 1]
+ * arrDropWhile([2, 4, 6, 1, 8], x => x % 2 === 0); // [1, 8]
+ * arrDropWhile([1, 2, 3], x => x > 5); // [1, 2, 3]
+ * arrDropWhile([1, 2, 3], x => x < 5); // []
+ *
+ * // Array-like objects
+ * arrDropWhile({ length: 4, 0: 1, 1: 2, 2: 3, 3: 4 }, x => x < 3); // [3, 4]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrDropWhile(
+ theArray: ArrayLike | null | undefined,
+ callbackFn: ArrPredicateCallbackFn | ArrPredicateCallbackFn2,
+ thisArg?: any
+): T[] {
+ let result: T[];
+
+ if (isArrayLike(theArray)) {
+ arrForEach(theArray, (item, index) => {
+ if (!fnCall(callbackFn, thisArg, item, index, theArray as any)) {
+ result = arrSlice(theArray, index);
+ return -1; // Break out of forEach
+ }
+ });
+ }
+
+ return result || [];
+}
diff --git a/lib/src/array/fill.ts b/lib/src/array/fill.ts
new file mode 100644
index 00000000..5243f605
--- /dev/null
+++ b/lib/src/array/fill.ts
@@ -0,0 +1,81 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { ArrProto, UNDEF_VALUE, UNDEFINED } from "../internal/constants";
+import { _unwrapFunctionWithPoly } from "../internal/unwrapFunction";
+import { isArrayLike } from "../helpers/base";
+import { getLength } from "../helpers/length";
+import { WritableArrayLike } from "../helpers/arrayLike";
+import { mathMax, mathMin } from "../math/min_max";
+
+/**
+ * The arrFill() method changes all elements in an array to a static value, from a start index
+ * (default 0) to an end index (default array.length). It returns the modified array.
+ * This method mutates the array.
+ * @function
+ * @since 0.14.0
+ * @group Array
+ * @typeParam T - Identifies the type of array elements
+ * @param theArray - The array to fill
+ * @param value - Value to fill the array with
+ * @param start - Start index (inclusive), defaults to 0. Negative index counts from the end
+ * @param end - End index (exclusive), defaults to array.length. Negative index counts from the end
+ * @returns The modified array
+ * @example
+ * ```ts
+ * arrFill([1, 2, 3], 0); // [0, 0, 0]
+ * arrFill([1, 2, 3], 4, 1); // [1, 4, 4]
+ * arrFill([1, 2, 3], 5, 1, 2); // [1, 5, 3]
+ * arrFill([1, 2, 3], 6, -2); // [1, 6, 6]
+ * arrFill([1, 2, 3], 7, -3, -1); // [7, 7, 3]
+ * arrFill([], 1); // []
+ * ```
+ */
+export const arrFill = (/*#__PURE__*/_unwrapFunctionWithPoly("fill", ArrProto, polyArrFill) as (theArray: WritableArrayLike, value: T, start?: number, end?: number) => WritableArrayLike);
+
+/**
+ * Polyfill implementation of Array.fill() for environments that don't support it.
+ * @function
+ * @since 0.14.0
+ * @group Array
+ * @group Polyfill
+ * @typeParam T - Identifies the type of array elements
+ * @param theArray - The array to fill
+ * @param value - Value to fill the array with
+ * @param start - Start index (inclusive), defaults to 0
+ * @param end - End index (exclusive), defaults to array.length
+ * @returns The modified array
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function polyArrFill(theArray: WritableArrayLike, value: T, start?: number, end?: number): WritableArrayLike {
+ if (isArrayLike(theArray)) {
+ const len = getLength(theArray);
+ let startIdx = start === UNDEF_VALUE ? 0 : start;
+ let endIdx = end === UNDEF_VALUE ? len : end;
+
+ // Handle negative indices
+ if (startIdx < 0) {
+ startIdx = mathMax(len + startIdx, 0);
+ } else {
+ startIdx = mathMin(startIdx, len);
+ }
+
+ if (endIdx < 0) {
+ endIdx = mathMax(len + endIdx, 0);
+ } else {
+ endIdx = mathMin(endIdx, len);
+ }
+
+ // Fill the array
+ for (let i = startIdx; i < endIdx; i++) {
+ theArray[i] = value;
+ }
+ }
+
+ return theArray;
+}
diff --git a/lib/src/array/flatten.ts b/lib/src/array/flatten.ts
new file mode 100644
index 00000000..1f513ccc
--- /dev/null
+++ b/lib/src/array/flatten.ts
@@ -0,0 +1,69 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { isArray, isArrayLike, isUndefined } from "../helpers/base";
+import { arrForEach } from "./forEach";
+
+function _addItems(result: any[], arr: any, d: number): void {
+ const arrLen = arr.length;
+ let arrIdx = 0;
+
+ while (arrIdx < arrLen) {
+ const item = arr[arrIdx];
+ if (d > 0 && isArray(item)) {
+ _addItems(result, item, d - 1);
+ } else {
+ result.push(item);
+ }
+
+ arrIdx++;
+ }
+}
+
+
+/**
+ * The arrFlatten() method returns a new array with all sub-array elements flattened
+ * up to the specified depth (default 1).
+ * @function
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @param theArray - The array or array-like object to flatten
+ * @param depth - The flattening depth, defaults to 1. Use Infinity for complete flattening
+ * @returns A new flattened array
+ * @example
+ * ```ts
+ * arrFlatten([1, [2, 3], [4, [5, 6]]]); // [1, 2, 3, 4, [5, 6]]
+ * arrFlatten([1, [2, 3], [4, [5, 6]]], 2); // [1, 2, 3, 4, 5, 6]
+ * arrFlatten([1, [2, 3], [4, [5, 6]]], Infinity); // [1, 2, 3, 4, 5, 6]
+ * arrFlatten([1, 2, 3]); // [1, 2, 3]
+ * arrFlatten([]); // []
+ *
+ * // With array-like objects
+ * arrFlatten({ length: 2, 0: 1, 1: [2, 3] }); // [1, 2, 3]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrFlatten(theArray: ArrayLike | null | undefined, depth?: number): any[] {
+ const result: any[] = [];
+
+ if (isArrayLike(theArray)) {
+ const d = isUndefined(depth) ? 1 : depth;
+
+ arrForEach(theArray, (item) => {
+ if (d > 0 && isArray(item)) {
+ _addItems(result, item, d - 1);
+ } else {
+ result.push(item);
+ }
+ });
+ }
+
+ return result;
+}
diff --git a/lib/src/array/groupBy.ts b/lib/src/array/groupBy.ts
new file mode 100644
index 00000000..d03d8711
--- /dev/null
+++ b/lib/src/array/groupBy.ts
@@ -0,0 +1,70 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { isArrayLike, isFunction } from "../helpers/base";
+import { objHasOwn } from "../object/has_own";
+import { asString } from "../string/as_string";
+import { isSymbol } from "../symbol/symbol";
+import { arrForEach } from "./forEach";
+
+/**
+ * Callback function type for arrGroupBy
+ * @typeParam T - Identifies the base type of array elements
+ */
+export type ArrGroupByCallbackFn = (value: T, index: number, array: ArrayLike) => string | number | symbol;
+
+/**
+ * The arrGroupBy() method groups array elements by the result of a callback function,
+ * returning an object where keys are group identifiers and values are arrays of grouped elements.
+ * @function
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @param theArray - The array or array-like object to group
+ * @param callbackFn - Function that determines the group key for each element
+ * @param thisArg - The value to use as 'this' when executing callbackFn
+ * @returns An object with group keys as properties and arrays of grouped elements as values
+ * @example
+ * ```ts
+ * const numbers = [1, 2, 3, 4, 5, 6];
+ * const grouped = arrGroupBy(numbers, (n) => n % 2 === 0 ? "even" : "odd");
+ * // { odd: [1, 3, 5], even: [2, 4, 6] }
+ *
+ * const people = [
+ * { name: "Alice", age: 30 },
+ * { name: "Bob", age: 25 },
+ * { name: "Charlie", age: 30 }
+ * ];
+ * const byAge = arrGroupBy(people, (p) => p.age);
+ * // { "25": [{ name: "Bob", age: 25 }], "30": [{ name: "Alice", age: 30 }, { name: "Charlie", age: 30 }] }
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrGroupBy(
+ theArray: ArrayLike | null | undefined,
+ callbackFn: ArrGroupByCallbackFn,
+ thisArg?: any
+): Record {
+ const result: Record = {};
+
+ if (isArrayLike(theArray) && isFunction(callbackFn)) {
+ arrForEach(theArray, (item, idx) => {
+ const keyVal = callbackFn.call(thisArg, item, idx, theArray);
+ const theKey = isSymbol(keyVal) ? keyVal : asString(keyVal);
+
+ if (!objHasOwn(result, theKey)) {
+ result[theKey] = [];
+ }
+
+ result[theKey].push(item);
+ });
+ }
+
+ return result;
+}
diff --git a/lib/src/array/intersection.ts b/lib/src/array/intersection.ts
new file mode 100644
index 00000000..4ea42a87
--- /dev/null
+++ b/lib/src/array/intersection.ts
@@ -0,0 +1,61 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { isArrayLike } from "../helpers/base";
+import { arrForEach } from "./forEach";
+import { arrIncludes } from "./includes";
+
+/**
+ * The arrIntersection() method returns a new array containing elements that exist in all provided arrays.
+ * Uses strict equality (===) for comparison and maintains order from the first array.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @param arrays - Two or more arrays to intersect
+ * @returns A new array containing elements common to all arrays
+ * @example
+ * ```ts
+ * arrIntersection([1, 2, 3], [2, 3, 4]); // [2, 3]
+ * arrIntersection([1, 2, 3], [2, 3], [3, 4]); // [3]
+ * arrIntersection(["a", "b"], ["b", "c"]); // ["b"]
+ * arrIntersection([1, 2], [3, 4]); // []
+ * arrIntersection([1, 2, 3], []); // []
+ *
+ * // Array-like objects
+ * arrIntersection({ length: 3, 0: 1, 1: 2, 2: 3 }, [2, 3]); // [2, 3]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrIntersection(...arrays: ArrayLike[]): T[];
+export function arrIntersection(): T[] {
+ const result: T[] = [];
+ let theArrays = arguments;
+
+ if (theArrays.length > 0) {
+
+ const firstArray = theArrays[0];
+ if (isArrayLike(firstArray)) {
+ arrForEach(firstArray, (item) => {
+ let inAll = true;
+ arrForEach(theArrays, (arr, index) => {
+ if (index > 0 && !arrIncludes(arr, item)) {
+ inAll = false;
+ return -1; // Break out of forEach
+ }
+ });
+
+ if (inAll && !arrIncludes(result, item)) {
+ result.push(item);
+ }
+ });
+ }
+ }
+
+ return result;
+}
diff --git a/lib/src/array/partition.ts b/lib/src/array/partition.ts
new file mode 100644
index 00000000..310df278
--- /dev/null
+++ b/lib/src/array/partition.ts
@@ -0,0 +1,59 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { isArrayLike } from "../helpers/base";
+import { ArrPredicateCallbackFn, ArrPredicateCallbackFn2 } from "./callbacks";
+import { arrForEach } from "./forEach";
+
+/**
+ * The arrPartition() method splits an array into two arrays based on a predicate function.
+ * The first array contains elements for which the predicate returns true, the second contains the rest.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @typeParam E - Identifies the narrowed type when using type guards
+ * @param theArray - The array or array-like object to partition
+ * @param callbackFn - Function to test each element. Return true to include in first array, false for second
+ * @param thisArg - Optional value to use as `this` when executing callbackFn
+ * @returns A tuple of two arrays: [matching elements, non-matching elements]
+ * @example
+ * ```ts
+ * arrPartition([1, 2, 3, 4, 5], x => x % 2 === 0); // [[2, 4], [1, 3, 5]]
+ * arrPartition(["a", "bb", "ccc"], x => x.length > 1); // [["bb", "ccc"], ["a"]]
+ *
+ * // With type guard
+ * const mixed: (string | number)[] = [1, "a", 2, "b"];
+ * const [strings, numbers] = arrPartition(mixed, (x): x is string => typeof x === "string");
+ * // strings: string[], numbers: (string | number)[]
+ *
+ * // Array-like objects
+ * arrPartition({ length: 4, 0: 1, 1: 2, 2: 3, 3: 4 }, x => x > 2); // [[3, 4], [1, 2]]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrPartition(
+ theArray: ArrayLike | null | undefined,
+ callbackFn: ArrPredicateCallbackFn | ArrPredicateCallbackFn2,
+ thisArg?: any
+): [T[] | E[], T[]] {
+ const truthy: T[] = [];
+ const falsy: T[] = [];
+
+ if (isArrayLike(theArray)) {
+ arrForEach(theArray, (value, index, array) => {
+ if (callbackFn.call(thisArg, value, index, array)) {
+ truthy.push(value);
+ } else {
+ falsy.push(value);
+ }
+ });
+ }
+
+ return [truthy as any, falsy];
+}
diff --git a/lib/src/array/reverse.ts b/lib/src/array/reverse.ts
new file mode 100644
index 00000000..c9121ff7
--- /dev/null
+++ b/lib/src/array/reverse.ts
@@ -0,0 +1,38 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { WritableArrayLike } from "../helpers/arrayLike";
+import { ArrProto } from "../internal/constants";
+import { _unwrapFunction } from "../internal/unwrapFunction";
+
+/**
+ * The arrReverse() method reverses an array in place and returns the reference to the same array.
+ * The first array element becomes the last, and the last array element becomes the first.
+ * If you want to reverse an array without modifying the original, use arrSlice() first.
+ * @function
+ * @since 0.14.0
+ * @group Array
+ * @param theArray - The array to reverse
+ * @returns The reversed array (same reference as input)
+ * @example
+ * ```ts
+ * const arr1 = [1, 2, 3];
+ * arrReverse(arr1); // [3, 2, 1]
+ * // arr1 is now [3, 2, 1]
+ *
+ * arrReverse(["a", "b", "c"]); // ["c", "b", "a"]
+ * arrReverse([1]); // [1]
+ * arrReverse([]); // []
+ *
+ * // Non-mutating usage
+ * const original = [1, 2, 3];
+ * const reversed = arrReverse(arrSlice(original));
+ * // original: [1, 2, 3], reversed: [3, 2, 1]
+ * ```
+ */
+export const arrReverse: (theArray: WritableArrayLike) => WritableArrayLike = (/*#__PURE__*/_unwrapFunction("reverse", ArrProto));
diff --git a/lib/src/array/rotate.ts b/lib/src/array/rotate.ts
new file mode 100644
index 00000000..de72b0a0
--- /dev/null
+++ b/lib/src/array/rotate.ts
@@ -0,0 +1,69 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { arrSlice } from "./slice";
+import { getLength } from "../helpers/length";
+import { isArrayLike } from "../helpers/base";
+import { arrAppend } from "./append";
+
+/**
+ * The arrRotate() method returns a new array with elements rotated by the specified number of positions.
+ * Positive values rotate left (elements shift forward), negative values rotate right
+ * (elements shift backward). The original array is not modified.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the type of array elements
+ * @param theArray - The array or array-like object to rotate
+ * @param count - Number of positions to rotate. Positive = right, negative = left
+ * @returns A new array with elements rotated
+ * @example
+ * ```ts
+ * arrRotate([1, 2, 3, 4, 5], 2); // [3, 4, 5, 1, 2]
+ * arrRotate([1, 2, 3, 4, 5], -2); // [4, 5, 1, 2, 3]
+ * arrRotate([1, 2, 3], 0); // [1, 2, 3]
+ * arrRotate([1, 2, 3], 3); // [1, 2, 3] (full rotation)
+ * arrRotate([1, 2, 3], 5); // [3, 1, 2] (wraps around)
+ * arrRotate([1, 2, 3], -5); // [2, 3, 1] (wraps around)
+ * arrRotate([], 3); // []
+ *
+ * // Array-like objects
+ * arrRotate({ length: 3, 0: "a", 1: "b", 2: "c" }, 1); // ["b", "c", "a"]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrRotate(theArray: ArrayLike | null | undefined, count: number): T[] {
+ let result: T[];
+
+ if (isArrayLike(theArray)) {
+ const len = theArray.length;
+
+ if (!(len === 0 || count === 0)) {
+ // Normalize the rotation count to be within array bounds
+ let rotations = count % len;
+ if (rotations < 0) {
+ rotations = len + rotations;
+ }
+
+ // If no effective rotation needed
+ if (rotations !== 0) {
+ // Split at rotation point and recombine
+ // For positive count: rotate left (elements shift forward)
+ result = [];
+ arrAppend(result, arrSlice(theArray, rotations));
+ arrAppend(result, arrSlice(theArray, 0, rotations));
+ }
+ }
+
+ if (!result) {
+ result = arrSlice(theArray);
+ }
+ }
+
+ return result || [];
+}
diff --git a/lib/src/array/sample.ts b/lib/src/array/sample.ts
new file mode 100644
index 00000000..5a73d8b1
--- /dev/null
+++ b/lib/src/array/sample.ts
@@ -0,0 +1,48 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { isArrayLike } from "../helpers/base";
+import { mathFloor } from "../math/floor";
+import { mathRandom } from "../math/random";
+import { getLength } from "../helpers/length";
+
+/**
+ * The arrSample() method returns a random element from the array.
+ * Returns undefined if the array is empty or null/undefined.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @param theArray - The array or array-like object to sample from
+ * @returns A random element from the array, or undefined if empty
+ * @example
+ * ```ts
+ * arrSample([1, 2, 3, 4, 5]); // e.g., 3
+ * arrSample(["a", "b", "c"]); // e.g., "b"
+ * arrSample([42]); // 42
+ * arrSample([]); // undefined
+ * arrSample(null); // undefined
+ *
+ * // Array-like objects
+ * arrSample({ length: 3, 0: "x", 1: "y", 2: "z" }); // e.g., "y"
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrSample(theArray: ArrayLike | null | undefined): T | undefined {
+ let result: T | undefined;
+
+ if (isArrayLike(theArray)) {
+ const len = getLength(theArray);
+ if (len !== 0) {
+ const index = mathFloor(mathRandom() * len);
+ result = theArray[index];
+ }
+ }
+
+ return result;
+}
diff --git a/lib/src/array/shuffle.ts b/lib/src/array/shuffle.ts
new file mode 100644
index 00000000..e6901ad5
--- /dev/null
+++ b/lib/src/array/shuffle.ts
@@ -0,0 +1,48 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { mathFloor } from "../math/floor";
+import { mathRandom } from "../math/random";
+import { getLength } from "../helpers/length";
+import { arrSlice } from "./slice";
+
+/**
+ * The arrShuffle() method returns a new array with elements randomly shuffled.
+ * Uses the Fisher-Yates shuffle algorithm for uniform randomization.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @param theArray - The array or array-like object to shuffle
+ * @returns A new array with elements in random order
+ * @example
+ * ```ts
+ * arrShuffle([1, 2, 3, 4, 5]); // e.g., [3, 1, 5, 2, 4]
+ * arrShuffle(["a", "b", "c"]); // e.g., ["c", "a", "b"]
+ * arrShuffle([1]); // [1]
+ * arrShuffle([]); // []
+ *
+ * // Array-like objects
+ * arrShuffle({ length: 3, 0: "x", 1: "y", 2: "z" }); // e.g., ["z", "x", "y"]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrShuffle(theArray: ArrayLike | null | undefined): T[] {
+ const result = arrSlice(theArray);
+ const len = getLength(result);
+
+ // Fisher-Yates shuffle
+ for (let i = len - 1; i > 0; i--) {
+ const swapVal = result[i];
+ const j = mathFloor(mathRandom() * (i + 1));
+ result[i] = result[j];
+ result[j] = swapVal;
+ }
+
+ return result;
+}
diff --git a/lib/src/array/take.ts b/lib/src/array/take.ts
new file mode 100644
index 00000000..1c7cfe76
--- /dev/null
+++ b/lib/src/array/take.ts
@@ -0,0 +1,37 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { arrSlice } from "./slice";
+import { mathMax } from "../math/min_max";
+
+/**
+ * The arrTake() method returns a new array with the first n elements from the source array.
+ * If n is greater than the array length, returns all elements. If n is negative or 0, returns empty array.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @param theArray - The array or array-like object to take from
+ * @param count - The number of elements to take from the beginning
+ * @returns A new array containing the first n elements
+ * @example
+ * ```ts
+ * arrTake([1, 2, 3, 4, 5], 3); // [1, 2, 3]
+ * arrTake(["a", "b", "c"], 2); // ["a", "b"]
+ * arrTake([1, 2], 5); // [1, 2]
+ * arrTake([1, 2, 3], 0); // []
+ * arrTake([1, 2, 3], -1); // []
+ *
+ * // Array-like objects
+ * arrTake({ length: 4, 0: 1, 1: 2, 2: 3, 3: 4 }, 2); // [1, 2]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrTake(theArray: ArrayLike | null | undefined, count: number): T[] {
+ return arrSlice(theArray, 0, mathMax(0, count));
+}
diff --git a/lib/src/array/take_while.ts b/lib/src/array/take_while.ts
new file mode 100644
index 00000000..8e407132
--- /dev/null
+++ b/lib/src/array/take_while.ts
@@ -0,0 +1,56 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { isArrayLike } from "../helpers/base";
+import { getLength } from "../helpers/length";
+import { ArrPredicateCallbackFn, ArrPredicateCallbackFn2 } from "./callbacks";
+import { arrForEach } from "./forEach";
+
+/**
+ * The arrTakeWhile() method returns a new array containing elements from the beginning of the array
+ * as long as the predicate function returns true. Once the predicate returns false, iteration stops.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @typeParam E - Identifies the narrowed type when using type guards
+ * @param theArray - The array or array-like object to take from
+ * @param callbackFn - Function to test each element. Return true to continue, false to stop
+ * @param thisArg - Optional value to use as `this` when executing callbackFn
+ * @returns A new array containing elements until the predicate returns false
+ * @example
+ * ```ts
+ * arrTakeWhile([1, 2, 3, 4, 1], x => x < 3); // [1, 2]
+ * arrTakeWhile([2, 4, 6, 1, 8], x => x % 2 === 0); // [2, 4, 6]
+ * arrTakeWhile([1, 2, 3], x => x > 5); // []
+ * arrTakeWhile([1, 2, 3], x => x < 5); // [1, 2, 3]
+ *
+ * // Array-like objects
+ * arrTakeWhile({ length: 4, 0: 1, 1: 2, 2: 3, 3: 4 }, x => x < 3); // [1, 2]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrTakeWhile(
+ theArray: ArrayLike | null | undefined,
+ callbackFn: ArrPredicateCallbackFn | ArrPredicateCallbackFn2,
+ thisArg?: any
+): T[] | E[] {
+ const result: T[] = [];
+
+ if (isArrayLike(theArray)) {
+ arrForEach(theArray, (value, idx) => {
+ if (!callbackFn.call(thisArg, value, idx, theArray as any)) {
+ return -1;
+ }
+
+ result.push(value);
+ });
+ }
+
+ return result as (T[] | E[]);
+}
diff --git a/lib/src/array/union.ts b/lib/src/array/union.ts
new file mode 100644
index 00000000..42b85fd1
--- /dev/null
+++ b/lib/src/array/union.ts
@@ -0,0 +1,46 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { arrUnique } from "./unique";
+import { arrAppend } from "./append";
+import { arrSlice } from "./slice";
+import { arrForEach } from "./forEach";
+
+/**
+ * The arrUnion() method returns a new array containing all unique elements from all provided arrays.
+ * Uses strict equality (===) for comparison and maintains insertion order.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @param arrays - One or more arrays to combine
+ * @returns A new array containing all unique elements from all arrays
+ * @example
+ * ```ts
+ * arrUnion([1, 2], [2, 3]); // [1, 2, 3]
+ * arrUnion([1, 2], [3, 4], [4, 5]); // [1, 2, 3, 4, 5]
+ * arrUnion(["a", "b"], ["b", "c"]); // ["a", "b", "c"]
+ * arrUnion([1, 1, 2], [2, 2, 3]); // [1, 2, 3]
+ * arrUnion([], [1, 2]); // [1, 2]
+ *
+ * // Array-like objects
+ * arrUnion({ length: 2, 0: 1, 1: 2 }, [2, 3]); // [1, 2, 3]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrUnion(...arrays: ArrayLike[]): T[];
+export function arrUnion(): T[] {
+ let combined: T[] = [];
+ let theArgs = arguments;
+
+ arrForEach(theArgs, (arr) => {
+ combined = arrAppend(combined, arrSlice(arr));
+ });
+
+ return arrUnique(combined);
+}
diff --git a/lib/src/array/unique.ts b/lib/src/array/unique.ts
new file mode 100644
index 00000000..ff6f8a7a
--- /dev/null
+++ b/lib/src/array/unique.ts
@@ -0,0 +1,55 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { isArrayLike } from "../helpers/base";
+import { normalizeJsName } from "../helpers/encode";
+import { objCreate } from "../object/create";
+import { objHasOwn } from "../object/has_own";
+import { arrForEach } from "./forEach";
+
+/**
+ * The arrUnique() method returns a new array with duplicate elements removed.
+ * Uses strict equality (===) for comparison and maintains insertion order.
+ * @function
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @param theArray - The array or array-like object to remove duplicates from
+ * @returns A new array with duplicate values removed, preserving order of first occurrence
+ * @example
+ * ```ts
+ * arrUnique([1, 2, 2, 3, 1, 4]); // [1, 2, 3, 4]
+ * arrUnique(["a", "b", "a", "c"]); // ["a", "b", "c"]
+ * arrUnique([1, "1", 1, "1"]); // [1, "1"]
+ * arrUnique([]); // []
+ * arrUnique([1]); // [1]
+ *
+ * // Array-like objects
+ * arrUnique({ length: 4, 0: 1, 1: 2, 2: 2, 3: 3 }); // [1, 2, 3]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrUnique(theArray: ArrayLike | null | undefined): T[] {
+ const result: T[] = [];
+
+ if (isArrayLike(theArray)) {
+ const seen: any = objCreate(null);
+
+ arrForEach(theArray, (item) => {
+ const key = ((typeof item) + "_" + item);
+
+ if (!objHasOwn(seen, key)) {
+ seen[key] = 1;
+ result.push(item);
+ }
+ });
+ }
+
+ return result;
+}
diff --git a/lib/src/array/unzip.ts b/lib/src/array/unzip.ts
new file mode 100644
index 00000000..608af109
--- /dev/null
+++ b/lib/src/array/unzip.ts
@@ -0,0 +1,76 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { isArrayLike } from "../helpers/base";
+import { getLength } from "../helpers/length";
+import { UNDEF_VALUE } from "../internal/constants";
+import { arrForEach } from "./forEach";
+
+/**
+ * The arrUnzip() method reverses the operation of arrZip(). Given an array of grouped elements,
+ * it creates multiple arrays where each contains elements from the same position in each group.
+ * This is the inverse operation of arrZip().
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @param theArray - An array of arrays to unzip
+ * @returns An array of arrays, ungrouped by position
+ * @example
+ * ```ts
+ * arrUnzip([[1, "a"], [2, "b"], [3, "c"]]); // [[1, 2, 3], ["a", "b", "c"]]
+ * arrUnzip([[1, "a", true], [2, "b", false]]); // [[1, 2], ["a", "b"], [true, false]]
+ * arrUnzip([[1], [2], [3]]); // [[1, 2, 3]]
+ * arrUnzip([]); // []
+ *
+ * // Array-like objects
+ * arrUnzip({ length: 2, 0: [1, "x"], 1: [2, "y"] }); // [[1, 2], ["x", "y"]]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrUnzip(theArray: ArrayLike> | null | undefined): any[][] {
+ let result: any[][];
+
+ if (isArrayLike(theArray)) {
+ const len = getLength(theArray);
+
+ if (len !== 0) {
+ // Find the maximum length among all sub-arrays
+ let maxLen = 0;
+
+ arrForEach(theArray, (subArray) => {
+ if (isArrayLike(subArray)) {
+ const subLen = getLength(subArray);
+
+ if (subLen > maxLen) {
+ maxLen = subLen;
+ }
+ }
+ });
+
+ if (maxLen !== 0) {
+ // Create result arrays
+ result = [];
+
+ for (let lp = 0; lp < maxLen; lp++) {
+ result.push([]);
+ }
+
+ // Fill result arrays
+ arrForEach(theArray, (subArray) => {
+ if (isArrayLike(subArray)) {
+ for (let lp = 0; lp < maxLen; lp++) {
+ result[lp].push(lp < getLength(subArray) ? subArray[lp] : UNDEF_VALUE);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ return result || [];
+}
diff --git a/lib/src/array/with.ts b/lib/src/array/with.ts
new file mode 100644
index 00000000..7e93a709
--- /dev/null
+++ b/lib/src/array/with.ts
@@ -0,0 +1,84 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { ArrProto } from "../internal/constants";
+import { _unwrapFunctionWithPoly } from "../internal/unwrapFunction";
+import { isArrayLike } from "../helpers/base";
+import { getLength } from "../helpers/length";
+import { arrSlice } from "./slice";
+
+/**
+ * The arrWith() method is the copying version of using the bracket notation to change the value
+ * of a given index. It returns a new array with the element at the given index replaced with the
+ * given value. This is an ES2023 feature with polyfill support for older environments.
+ * @function
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @typeParam T - Identifies the type of array elements
+ * @param theArray - The array or array-like object to copy from
+ * @param index - The index at which to change the value. Negative index counts from the end
+ * @param value - The new value to set at the index
+ * @returns A new array with the element at index replaced, or the original array if index is out of range
+ * @example
+ * ```ts
+ * arrWith([1, 2, 3], 1, 5); // [1, 5, 3]
+ * arrWith([1, 2, 3], -1, 5); // [1, 2, 5]
+ * arrWith([1, 2, 3], -2, 5); // [1, 5, 3]
+ * arrWith([1, 2, 3], 10, 5); // RangeError (out of bounds)
+ *
+ * const original = [1, 2, 3];
+ * const modified = arrWith(original, 1, 9);
+ * // original: [1, 2, 3], modified: [1, 9, 3]
+ *
+ * // Array-like objects
+ * arrWith({ length: 3, 0: "a", 1: "b", 2: "c" }, 1, "x"); // ["a", "x", "c"]
+ * ```
+ */
+export const arrWith = (/*#__PURE__*/_unwrapFunctionWithPoly("with", ArrProto as any, polyArrWith) as (theArray: ArrayLike, index: number, value: T) => T[]);
+
+/**
+ * Polyfill implementation of Array.with() for environments that don't support it.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @group Polyfill
+ * @typeParam T - Identifies the type of array elements
+ * @param theArray - The array or array-like object to copy from
+ * @param index - The index at which to change the value
+ * @param value - The new value to set at the index
+ * @returns A new array with the element at index replaced
+ * @throws RangeError if the index is out of bounds
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function polyArrWith(theArray: ArrayLike, index: number, value: T): T[] {
+ let result: T[];
+
+ if (!isArrayLike(theArray)) {
+ throw new RangeError("Invalid array");
+ }
+
+ const len = getLength(theArray);
+ let idx = index;
+
+ // Convert negative index to positive
+ if (idx < 0) {
+ idx = len + idx;
+ }
+
+ // Check bounds
+ if (idx < 0 || idx >= len) {
+ throw new RangeError("Index out of bounds");
+ }
+
+ // Create a copy and set value
+ result = arrSlice(theArray);
+ result[idx] = value;
+
+ return result;
+}
diff --git a/lib/src/array/zip.ts b/lib/src/array/zip.ts
new file mode 100644
index 00000000..72c14e58
--- /dev/null
+++ b/lib/src/array/zip.ts
@@ -0,0 +1,72 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { isArrayLike } from "../helpers/base";
+import { getLength } from "../helpers/length";
+import { mathMin } from "../math/min_max";
+
+/**
+ * The arrZip() method creates a new array of grouped elements, where the first array contains
+ * the first elements of each input array, the second array contains the second elements, and so on.
+ * The length of the result is determined by the shortest input array.
+ * @since 0.14.0
+ * @group Array
+ * @group ArrayLike
+ * @param arrays - Two or more arrays to zip together
+ * @returns A new array of arrays, grouped by index
+ * @example
+ * ```ts
+ * arrZip([1, 2, 3], ["a", "b", "c"]); // [[1, "a"], [2, "b"], [3, "c"]]
+ * arrZip([1, 2], ["a", "b", "c"]); // [[1, "a"], [2, "b"]]
+ * arrZip([1, 2, 3], ["a", "b"], [true, false]); // [[1, "a", true], [2, "b", false]]
+ * arrZip([1], []); // []
+ *
+ * // Array-like objects
+ * arrZip({ length: 2, 0: 1, 1: 2 }, ["x", "y"]); // [[1, "x"], [2, "y"]]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrZip(...arrays: ArrayLike[]): any[][] {
+ let result: any[][];
+
+ if (arrays.length !== 0) {
+ // Filter out null/undefined arrays and find the minimum length
+ const validArrays: ArrayLike[] = [];
+
+ for (let i = 0; i < arrays.length; i++) {
+ if (isArrayLike(arrays[i])) {
+ validArrays.push(arrays[i]);
+ }
+ }
+
+ if (validArrays.length !== 0) {
+ // Find the minimum length among all valid arrays
+ let minLen = Infinity;
+
+ for (let lp = 0; lp < validArrays.length; lp++) {
+ minLen = mathMin(minLen, getLength(validArrays[lp]));
+ }
+
+ if (isFinite(minLen) && minLen !== 0) {
+ result = [];
+
+ for (let lp = 0; lp < minLen; lp++) {
+ const group: any[] = [];
+
+ for (let j = 0; j < validArrays.length; j++) {
+ group.push(validArrays[j][lp]);
+ }
+
+ result.push(group);
+ }
+ }
+ }
+ }
+
+ return result || [];
+}
diff --git a/lib/src/helpers/arrayLike.ts b/lib/src/helpers/arrayLike.ts
new file mode 100644
index 00000000..a42f903b
--- /dev/null
+++ b/lib/src/helpers/arrayLike.ts
@@ -0,0 +1,25 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+/**
+ * Writable (mutable) ArrayLike interface.
+ * This is similar to the built-in ArrayLike, but with mutable properties.
+ * @since 0.14.0
+ * @group ArrayLike
+ * @typeParam T - Identifies the base type of array elements
+ * @example
+ * ```ts
+ * const buf: WritableArrayLike = { length: 3, 0: 1, 1: 2, 2: 3 };
+ * buf[1] = 42;
+ * buf.length = 4;
+ * ```
+ */
+export interface WritableArrayLike {
+ length: number;
+ [index: number]: T;
+}
diff --git a/lib/src/helpers/base.ts b/lib/src/helpers/base.ts
index 09bca689..f349cbaa 100644
--- a/lib/src/helpers/base.ts
+++ b/lib/src/helpers/base.ts
@@ -6,7 +6,7 @@
* Licensed under the MIT license.
*/
-import { ArrCls, FUNCTION, NULL_VALUE, OBJECT, ObjProto, TO_STRING, UNDEFINED, UNDEF_VALUE } from "../internal/constants";
+import { ArrCls, FUNCTION, LENGTH, NULL_VALUE, OBJECT, ObjProto, TO_STRING, UNDEFINED, UNDEF_VALUE } from "../internal/constants";
import { _isPolyfillType } from "../internal/poly_helpers";
import { _pureRef } from "../internal/treeshake_helpers";
import { safeGet } from "./safe_get";
@@ -542,6 +542,32 @@ export function isObject(value: T): value is T {
*/
export const isArray: (arg: any) => arg is Array = (/* #__PURE__*/_pureRef(ArrCls as any, "isArray"));
+/**
+ * Checks if the type of value is array-like (has a numeric length property and numeric indices).
+ * @since 0.14.0
+ * @function
+ * @group Type Identity
+ * @group Array
+ * @param arg - Value to be checked.
+ * @return True if the value is array-like, false otherwise.
+ * @example
+ * ```ts
+ * import { isArrayLike } from "@nevware21/ts-utils";
+ *
+ * isArrayLike([1, 2, 3]); // true
+ * isArrayLike("hello"); // true
+ * isArrayLike({ length: 3, 0: "a", 1: "b", 2: "c" }); // true
+ * isArrayLike({ length: "3" }); // false (length is not a number)
+ * isArrayLike({ 0: "a", 1: "b" }); // false (no length property)
+ * isArrayLike(null); // false
+ * isArrayLike(undefined); // false
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function isArrayLike(arg: any): arg is ArrayLike {
+ return !isStrictNullOrUndefined(arg) && !isFunction(arg) && isNumber(arg[LENGTH]) && arg[LENGTH] >= 0;
+}
+
/**
* Check if an object is of type Date
* @function
diff --git a/lib/src/index.ts b/lib/src/index.ts
index 0c5fb18e..59149f54 100644
--- a/lib/src/index.ts
+++ b/lib/src/index.ts
@@ -8,22 +8,45 @@
export { arrAppend } from "./array/append";
export { ArrPredicateCallbackFn, ArrPredicateCallbackFn2, ArrMapCallbackFn, ArrFromMapFn } from "./array/callbacks";
+export { arrAt } from "./array/at";
+export { arrChunk } from "./array/chunk";
+export { arrCompact } from "./array/compact";
+export { arrDifference } from "./array/difference";
+export { arrDrop } from "./array/drop";
+export { arrDropWhile } from "./array/drop_while";
export { arrEvery, arrFilter } from "./array/every";
+export { arrFill } from "./array/fill";
export { arrFind, arrFindIndex, arrFindLast, arrFindLastIndex } from "./array/find";
+export { arrFlatten } from "./array/flatten";
export { arrForEach } from "./array/forEach";
export { arrFrom } from "./array/from";
+export { ArrGroupByCallbackFn, arrGroupBy } from "./array/groupBy";
export { arrContains, arrIncludes } from "./array/includes";
export { arrIndexOf, arrLastIndexOf } from "./array/indexOf";
+export { arrIntersection } from "./array/intersection";
export { arrMap } from "./array/map";
+export { arrPartition } from "./array/partition";
export { ArrReduceCallbackFn, arrReduce } from "./array/reduce";
+export { arrReverse } from "./array/reverse";
+export { arrRotate } from "./array/rotate";
+export { arrSample } from "./array/sample";
+export { arrShuffle } from "./array/shuffle";
export { arrSlice } from "./array/slice";
export { arrSome } from "./array/some";
+export { arrTake } from "./array/take";
+export { arrTakeWhile } from "./array/take_while";
+export { arrUnion } from "./array/union";
+export { arrUnique } from "./array/unique";
+export { arrUnzip } from "./array/unzip";
+export { arrWith } from "./array/with";
+export { arrZip } from "./array/zip";
export { fnApply, fnBind, fnCall } from "./funcs/funcs";
export { createFnDeferredProxy, createProxyFuncs } from "./funcs/fnProxy";
export { readArgs } from "./funcs/readArgs";
export { ProxyFunctionDef, TypeFuncNames } from "./funcs/types";
+export { WritableArrayLike } from "./helpers/arrayLike";
export {
- isTypeof, isUndefined, isNullOrUndefined, isDefined, isString, isFunction, isObject, isArray, isDate, isNumber, isBoolean,
+ isTypeof, isUndefined, isNullOrUndefined, isDefined, isString, isFunction, isObject, isArray, isArrayLike, isDate, isNumber, isBoolean,
isRegExp, isFile, isFormData, isBlob, isArrayBuffer, isPromiseLike, isPromise, isThenable, isNotTruthy, isTruthy, objToString,
isStrictNullOrUndefined, isStrictUndefined, isError, isPrimitive, isPrimitiveType, isMap, isMapLike, isSet, isSetLike,
isWeakMap, isWeakSet, isBigInt, isAsyncFunction, isGenerator, isAsyncGenerator
diff --git a/lib/src/internal/unwrapFunction.ts b/lib/src/internal/unwrapFunction.ts
index 1c2ab8d6..1a09072b 100644
--- a/lib/src/internal/unwrapFunction.ts
+++ b/lib/src/internal/unwrapFunction.ts
@@ -22,7 +22,7 @@ import { ArrSlice, CALL, NULL_VALUE } from "./constants";
* @param funcName - The function name to call on the first argument passed to the wrapped function
* @returns A function which will call the funcName against the first passed argument and pass on the remaining arguments
*/
-export const _unwrapInstFunction:(funcName: keyof T) => (this: T, ..._args:any) => R = (/*#__PURE__*/_unwrapFunctionWithPoly);
+export const _unwrapInstFunction:(funcName: keyof T) => (this: T, ..._args:any) => R = _unwrapFunctionWithPoly;
/**
* @function
@@ -33,7 +33,7 @@ export const _unwrapInstFunction:(funcName: keyof T) => (this: T, ..._a
* @param clsProto - The Class or class prototype to fallback to if the instance doesn't have the function.
* @returns A function which will call the funcName against the first passed argument and pass on the remaining arguments
*/
-export const _unwrapFunction:(funcName: keyof T, clsProto: T) => (this: T, ..._args:any) => R = (/*#__PURE__*/_unwrapFunctionWithPoly);
+export const _unwrapFunction:(funcName: keyof T, clsProto: T) => (this: T, ..._args:any) => R = _unwrapFunctionWithPoly;
/**
* @internal
diff --git a/lib/src/polyfills.ts b/lib/src/polyfills.ts
index 2359270e..512fbeab 100644
--- a/lib/src/polyfills.ts
+++ b/lib/src/polyfills.ts
@@ -25,6 +25,9 @@ import { polyObjIsExtensible } from "./polyfills/object/objIsExtensible";
import { polyObjIsFrozen } from "./polyfills/object/objIsFrozen";
import { polyObjIsSealed } from "./polyfills/object/objIsSealed";
import { polyObjHasOwn } from "./object/has_own";
+import { polyArrAt } from "./array/at";
+import { polyArrFill } from "./array/fill";
+import { polyArrWith } from "./array/with";
(function () {
@@ -64,11 +67,14 @@ import { polyObjHasOwn } from "./object/has_own";
};
const arrayPolyfills = {
+ "at": polyArrAt,
+ "fill": polyArrFill,
"includes": polyArrIncludes,
"find": polyArrFind,
"findIndex": polyArrFindIndex,
"findLast": polyArrFindLast,
- "findLastIndex": polyArrFindLastIndex
+ "findLastIndex": polyArrFindLastIndex,
+ "with": polyArrWith
};
// Add Object polyfills
@@ -97,3 +103,5 @@ import { polyObjHasOwn } from "./object/has_own";
}
});
})();
+
+export { polyArrAt, polyArrFill, polyArrWith };
diff --git a/lib/test/bundle-size-check.js b/lib/test/bundle-size-check.js
index 215987f0..6d5dd6c6 100644
--- a/lib/test/bundle-size-check.js
+++ b/lib/test/bundle-size-check.js
@@ -7,31 +7,31 @@ const configs = [
{
name: "es5-min-full",
path: "../bundle/es5/umd/ts-utils.min.js",
- limit: 27.5 * 1024, // 27.5 kb in bytes
+ limit: 30.5 * 1024, // 30.5 kb in bytes
compress: false
},
{
name: "es6-min-full",
path: "../bundle/es6/umd/ts-utils.min.js",
- limit: 27 * 1024, // 27 kb in bytes
+ limit: 30 * 1024, // 30 kb in bytes
compress: false
},
{
name: "es5-min-zip",
path: "../bundle/es5/umd/ts-utils.min.js",
- limit: 11 * 1024, // 11 kb in bytes
+ limit: 12 * 1024, // 12 kb in bytes
compress: true
},
{
name: "es6-min-zip",
path: "../bundle/es6/umd/ts-utils.min.js",
- limit: 11 * 1024, // 11 kb in bytes
+ limit: 12 * 1024, // 12 kb in bytes
compress: true
},
{
name: "es5-min-poly",
path: "../bundle/es5/ts-polyfills-utils.min.js",
- limit: 8 * 1024, // 8 kb in bytes
+ limit: 9 * 1024, // 9 kb in bytes
compress: false
}
];
diff --git a/lib/test/src/common/array/at.test.ts b/lib/test/src/common/array/at.test.ts
new file mode 100644
index 00000000..97c6a257
--- /dev/null
+++ b/lib/test/src/common/array/at.test.ts
@@ -0,0 +1,107 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { arrAt, polyArrAt } from "../../../../src/array/at";
+
+describe("arrAt", () => {
+ it("should return element at positive index", () => {
+ assert.equal(arrAt([1, 2, 3], 0), 1);
+ assert.equal(arrAt([1, 2, 3], 1), 2);
+ assert.equal(arrAt([1, 2, 3], 2), 3);
+ });
+
+ it("should return element at negative index", () => {
+ assert.equal(arrAt([1, 2, 3], -1), 3);
+ assert.equal(arrAt([1, 2, 3], -2), 2);
+ assert.equal(arrAt([1, 2, 3], -3), 1);
+ });
+
+ it("should return undefined for out of bounds index", () => {
+ assert.isUndefined(arrAt([1, 2, 3], 5));
+ assert.isUndefined(arrAt([1, 2, 3], -5));
+ });
+
+ it("should handle empty array", () => {
+ assert.isUndefined(arrAt([], 0));
+ });
+
+ it("should throw for null and undefined", () => {
+ // Native .at() throws TypeError for null/undefined
+ assert.throws(() => arrAt(null, 0));
+ assert.throws(() => arrAt(undefined, 0));
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 3, 0: "a", 1: "b", 2: "c" };
+ assert.equal(arrAt(arrayLike, 0), "a");
+ assert.equal(arrAt(arrayLike, -1), "c");
+ });
+
+ it("should work with strings", () => {
+ assert.equal(arrAt("hello", 0), "h");
+ assert.equal(arrAt("hello", -1), "o");
+ });
+});
+
+describe("polyArrAt", () => {
+ it("should match native Array.prototype.at behavior for positive indices", () => {
+ const arr = [1, 2, 3, 4, 5];
+ for (let i = 0; i < arr.length; i++) {
+ assert.equal(
+ polyArrAt(arr, i),
+ (arr as any).at ? (arr as any).at(i) : arr[i],
+ `Index ${i} should match`
+ );
+ }
+ });
+
+ it("should match native Array.prototype.at behavior for negative indices", () => {
+ const arr = [1, 2, 3, 4, 5];
+ for (let i = -1; i >= -arr.length; i--) {
+ const polyResult = polyArrAt(arr, i);
+ const nativeResult = (arr as any).at ? (arr as any).at(i) : arr[arr.length + i];
+ assert.equal(polyResult, nativeResult, `Index ${i} should match`);
+ }
+ });
+
+ it("should return undefined for out of bounds like native", () => {
+ const arr = [1, 2, 3];
+ assert.isUndefined(polyArrAt(arr, 10));
+ assert.isUndefined(polyArrAt(arr, -10));
+
+ if ((arr as any).at) {
+ assert.equal(polyArrAt(arr, 10), (arr as any).at(10));
+ assert.equal(polyArrAt(arr, -10), (arr as any).at(-10));
+ }
+ });
+
+ it("should handle index 0", () => {
+ const arr = [42];
+ assert.equal(polyArrAt(arr, 0), 42);
+ if ((arr as any).at) {
+ assert.equal(polyArrAt(arr, 0), (arr as any).at(0));
+ }
+ });
+
+ it("should handle empty array like native", () => {
+ const arr: number[] = [];
+ assert.isUndefined(polyArrAt(arr, 0));
+ if ((arr as any).at) {
+ assert.equal(polyArrAt(arr, 0), (arr as any).at(0));
+ }
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 3, 0: "x", 1: "y", 2: "z" };
+ assert.equal(polyArrAt(arrayLike, 0), "x");
+ assert.equal(polyArrAt(arrayLike, -1), "z");
+ assert.equal(polyArrAt(arrayLike, 1), "y");
+ assert.equal(polyArrAt(arrayLike, -2), "y");
+ });
+});
diff --git a/lib/test/src/common/array/difference.test.ts b/lib/test/src/common/array/difference.test.ts
new file mode 100644
index 00000000..7cc37e8d
--- /dev/null
+++ b/lib/test/src/common/array/difference.test.ts
@@ -0,0 +1,60 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { arrDifference } from "../../../../src/array/difference";
+
+describe("arrDifference", () => {
+ it("should return elements in first array not in second array", () => {
+ assert.deepEqual(arrDifference([1, 2, 3, 4], [2, 4]), [1, 3]);
+ assert.deepEqual(arrDifference(["a", "b", "c"], ["b"]), ["a", "c"]);
+ });
+
+ it("should handle multiple exclude arrays", () => {
+ assert.deepEqual(arrDifference([1, 2, 3], [2], [3]), [1]);
+ assert.deepEqual(arrDifference([1, 2, 3, 4, 5], [2, 4], [3, 5]), [1]);
+ });
+
+ it("should return all elements when exclude arrays are empty", () => {
+ assert.deepEqual(arrDifference([1, 2, 3], []), [1, 2, 3]);
+ assert.deepEqual(arrDifference([1, 2, 3]), [1, 2, 3]);
+ });
+
+ it("should return empty array when source is empty", () => {
+ assert.deepEqual(arrDifference([], [1, 2]), []);
+ });
+
+ it("should handle null source array", () => {
+ assert.deepEqual(arrDifference(null, [1, 2]), []);
+ assert.deepEqual(arrDifference(undefined, [1, 2]), []);
+ });
+
+ it("should handle null exclude arrays", () => {
+ assert.deepEqual(arrDifference([1, 2, 3], null), [1, 2, 3]);
+ assert.deepEqual(arrDifference([1, 2, 3], undefined), [1, 2, 3]);
+ assert.deepEqual(arrDifference([1, 2, 3], [2], null), [1, 3]);
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 3, 0: 1, 1: 2, 2: 3 };
+ assert.deepEqual(arrDifference(arrayLike, [2]), [1, 3]);
+ });
+
+ it("should use strict equality", () => {
+ assert.deepEqual(arrDifference([1, 2, 3], ["1", "2"]), [1, 2, 3]);
+ assert.deepEqual(arrDifference(["1", "2", "3"], [1, 2]), ["1", "2", "3"]);
+ });
+
+ it("should preserve order from source array", () => {
+ assert.deepEqual(arrDifference([5, 3, 1, 4, 2], [3, 1]), [5, 4, 2]);
+ });
+
+ it("should handle duplicate values in source array", () => {
+ assert.deepEqual(arrDifference([1, 2, 2, 3, 3, 3], [2]), [1, 3, 3, 3]);
+ });
+});
diff --git a/lib/test/src/common/array/fill.test.ts b/lib/test/src/common/array/fill.test.ts
new file mode 100644
index 00000000..e4c54fb1
--- /dev/null
+++ b/lib/test/src/common/array/fill.test.ts
@@ -0,0 +1,151 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { arrFill, polyArrFill } from "../../../../src/array/fill";
+
+describe("arrFill", () => {
+ it("should fill entire array with value", () => {
+ const arr = [1, 2, 3, 4];
+ const result = arrFill(arr, 0);
+
+ assert.deepEqual(result, [0, 0, 0, 0]);
+ assert.deepEqual(arr, [0, 0, 0, 0]); // Mutates original
+ });
+
+ it("should fill from start index", () => {
+ const arr = [1, 2, 3, 4];
+ arrFill(arr, 0, 2);
+
+ assert.deepEqual(arr, [1, 2, 0, 0]);
+ });
+
+ it("should fill between start and end indices", () => {
+ const arr = [1, 2, 3, 4, 5];
+ arrFill(arr, 9, 1, 3);
+
+ assert.deepEqual(arr, [1, 9, 9, 4, 5]);
+ });
+
+ it("should handle negative start index", () => {
+ const arr = [1, 2, 3, 4];
+ arrFill(arr, 0, -2);
+
+ assert.deepEqual(arr, [1, 2, 0, 0]);
+ });
+
+ it("should handle negative end index", () => {
+ const arr = [1, 2, 3, 4];
+ arrFill(arr, 0, 0, -1);
+
+ assert.deepEqual(arr, [0, 0, 0, 4]);
+ });
+
+ it("should throw for null and undefined", () => {
+ // Native .fill() throws TypeError for null/undefined
+ assert.throws(() => arrFill(null, 0));
+ assert.throws(() => arrFill(undefined, 0));
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 3, 0: 1, 1: 2, 2: 3 };
+ const result = arrFill(arrayLike, 0);
+
+ assert.equal(result[0], 0);
+ assert.equal(result[1], 0);
+ assert.equal(result[2], 0);
+ });
+});
+
+describe("polyArrFill", () => {
+ it("should match native Array.prototype.fill for full fill", () => {
+ const arr1 = [1, 2, 3, 4];
+ const arr2 = [1, 2, 3, 4];
+
+ polyArrFill(arr1, 0);
+ if (arr2.fill) {
+ arr2.fill(0);
+ } else {
+ for (let i = 0; i < arr2.length; i++) {
+ arr2[i] = 0;
+ }
+ }
+
+ assert.deepEqual(arr1, arr2);
+ });
+
+ it("should match native Array.prototype.fill with start index", () => {
+ const arr1 = [1, 2, 3, 4];
+ const arr2 = [1, 2, 3, 4];
+
+ polyArrFill(arr1, 9, 2);
+ if (arr2.fill) {
+ arr2.fill(9, 2);
+ assert.deepEqual(arr1, arr2);
+ }
+ });
+
+ it("should match native Array.prototype.fill with start and end", () => {
+ const arr1 = [1, 2, 3, 4, 5];
+ const arr2 = [1, 2, 3, 4, 5];
+
+ polyArrFill(arr1, 8, 1, 3);
+ if (arr2.fill) {
+ arr2.fill(8, 1, 3);
+ assert.deepEqual(arr1, arr2);
+ }
+ });
+
+ it("should match native for negative indices", () => {
+ const arr1 = [1, 2, 3, 4];
+ const arr2 = [1, 2, 3, 4];
+
+ polyArrFill(arr1, 0, -2, -1);
+ if (arr2.fill) {
+ arr2.fill(0, -2, -1);
+ assert.deepEqual(arr1, arr2);
+ }
+ });
+
+ it("should mutate array like native", () => {
+ const arr = [1, 2, 3];
+ const result = polyArrFill(arr, 0);
+
+ assert.deepEqual(arr, [0, 0, 0]);
+ assert.strictEqual(result, arr); // Returns same reference
+
+ if (arr.fill) {
+ const arr2 = [1, 2, 3];
+ const result2 = arr2.fill(0);
+ assert.strictEqual(result2, arr2);
+ }
+ });
+
+ it("should handle empty array like native", () => {
+ const arr: number[] = [];
+ polyArrFill(arr, 5);
+
+ assert.deepEqual(arr, []);
+
+ if (arr.fill) {
+ const arr2: number[] = [];
+ arr2.fill(5);
+ assert.deepEqual(arr2, []);
+ }
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 4, 0: 1, 1: 2, 2: 3, 3: 4 };
+ polyArrFill(arrayLike, 0, 1, 3);
+
+ assert.equal(arrayLike[0], 1);
+ assert.equal(arrayLike[1], 0);
+ assert.equal(arrayLike[2], 0);
+ assert.equal(arrayLike[3], 4);
+ });
+});
diff --git a/lib/test/src/common/array/intersection.test.ts b/lib/test/src/common/array/intersection.test.ts
new file mode 100644
index 00000000..e2e41ffd
--- /dev/null
+++ b/lib/test/src/common/array/intersection.test.ts
@@ -0,0 +1,53 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { arrIntersection } from "../../../../src/array/intersection";
+
+describe("arrIntersection", () => {
+ it("should return common elements between two arrays", () => {
+ assert.deepEqual(arrIntersection([1, 2, 3], [2, 3, 4]), [2, 3]);
+ assert.deepEqual(arrIntersection(["a", "b"], ["b", "c"]), ["b"]);
+ });
+
+ it("should return common elements across multiple arrays", () => {
+ assert.deepEqual(arrIntersection([1, 2, 3], [2, 3], [3, 4]), [3]);
+ assert.deepEqual(arrIntersection([1, 2, 3, 4], [2, 3, 4], [3, 4, 5]), [3, 4]);
+ });
+
+ it("should return empty array when no common elements", () => {
+ assert.deepEqual(arrIntersection([1, 2], [3, 4]), []);
+ });
+
+ it("should return empty array when any array is empty", () => {
+ assert.deepEqual(arrIntersection([1, 2, 3], []), []);
+ });
+
+ it("should handle null and undefined", () => {
+ assert.deepEqual(arrIntersection(), []);
+ assert.deepEqual(arrIntersection(null, [1, 2]), []);
+ assert.deepEqual(arrIntersection(undefined, [1, 2]), []);
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 3, 0: 1, 1: 2, 2: 3 };
+ assert.deepEqual(arrIntersection(arrayLike, [2, 3]), [2, 3]);
+ });
+
+ it("should use strict equality", () => {
+ assert.deepEqual(arrIntersection([1, 2, 3], ["1", "2"]), []);
+ });
+
+ it("should preserve order from first array", () => {
+ assert.deepEqual(arrIntersection([5, 3, 1, 4, 2], [1, 2, 3, 4, 5]), [5, 3, 1, 4, 2]);
+ });
+
+ it("should remove duplicates from result", () => {
+ assert.deepEqual(arrIntersection([1, 2, 2, 3, 3], [2, 3]), [2, 3]);
+ });
+});
diff --git a/lib/test/src/common/array/partition.test.ts b/lib/test/src/common/array/partition.test.ts
new file mode 100644
index 00000000..d53fefbd
--- /dev/null
+++ b/lib/test/src/common/array/partition.test.ts
@@ -0,0 +1,68 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { arrPartition } from "../../../../src/array/partition";
+
+describe("arrPartition", () => {
+ it("should split array based on predicate", () => {
+ const [evens, odds] = arrPartition([1, 2, 3, 4, 5], x => x % 2 === 0);
+ assert.deepEqual(evens, [2, 4]);
+ assert.deepEqual(odds, [1, 3, 5]);
+ });
+
+ it("should handle string length predicate", () => {
+ const [long, short] = arrPartition(["a", "bb", "ccc"], x => x.length > 1);
+ assert.deepEqual(long, ["bb", "ccc"]);
+ assert.deepEqual(short, ["a"]);
+ });
+
+ it("should handle all matching predicate", () => {
+ const [match, noMatch] = arrPartition([2, 4, 6], x => x % 2 === 0);
+ assert.deepEqual(match, [2, 4, 6]);
+ assert.deepEqual(noMatch, []);
+ });
+
+ it("should handle no matching predicate", () => {
+ const [match, noMatch] = arrPartition([1, 3, 5], x => x % 2 === 0);
+ assert.deepEqual(match, []);
+ assert.deepEqual(noMatch, [1, 3, 5]);
+ });
+
+ it("should handle empty array", () => {
+ const [match, noMatch] = arrPartition([], x => x > 0);
+ assert.deepEqual(match, []);
+ assert.deepEqual(noMatch, []);
+ });
+
+ it("should handle null and undefined", () => {
+ const [m1, n1] = arrPartition(null, x => x > 0);
+ assert.deepEqual(m1, []);
+ assert.deepEqual(n1, []);
+
+ const [m2, n2] = arrPartition(undefined, x => x > 0);
+ assert.deepEqual(m2, []);
+ assert.deepEqual(n2, []);
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 4, 0: 1, 1: 2, 2: 3, 3: 4 };
+ const [evens, odds] = arrPartition(arrayLike, x => x % 2 === 0);
+ assert.deepEqual(evens, [2, 4]);
+ assert.deepEqual(odds, [1, 3]);
+ });
+
+ it("should support thisArg", () => {
+ const threshold = { value: 3 };
+ const [match, noMatch] = arrPartition([1, 2, 3, 4, 5], function(x) {
+ return x > this.value;
+ }, threshold);
+ assert.deepEqual(match, [4, 5]);
+ assert.deepEqual(noMatch, [1, 2, 3]);
+ });
+});
diff --git a/lib/test/src/common/array/reverse.test.ts b/lib/test/src/common/array/reverse.test.ts
new file mode 100644
index 00000000..91446f68
--- /dev/null
+++ b/lib/test/src/common/array/reverse.test.ts
@@ -0,0 +1,76 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { arrReverse } from "../../../../src/array/reverse";
+
+describe("arrReverse", () => {
+ it("should reverse array in place", () => {
+ const arr = [1, 2, 3, 4];
+ const result = arrReverse(arr);
+
+ assert.deepEqual(result, [4, 3, 2, 1]);
+ assert.deepEqual(arr, [4, 3, 2, 1]); // Mutates original
+ assert.strictEqual(result, arr); // Returns same reference
+ });
+
+ it("should handle single element array", () => {
+ const arr = [1];
+ arrReverse(arr);
+
+ assert.deepEqual(arr, [1]);
+ });
+
+ it("should handle empty array", () => {
+ const arr: number[] = [];
+ arrReverse(arr);
+
+ assert.deepEqual(arr, []);
+ });
+
+ it("should handle two element array", () => {
+ const arr = [1, 2];
+ arrReverse(arr);
+
+ assert.deepEqual(arr, [2, 1]);
+ });
+
+ it("should handle null and undefined", () => {
+ // arrReverse wraps native reverse which doesn't accept null/undefined
+ // These would throw TypeError in native implementation
+ assert.throws(() => arrReverse(null as any));
+ assert.throws(() => arrReverse(undefined as any));
+ });
+
+ it("should work with array-like objects after conversion", () => {
+ // Native reverse requires actual Array, not array-like
+ const arrayLike = { length: 3, 0: "a", 1: "b", 2: "c" };
+ // Convert to array first using Array.from or arrSlice
+ const arr = Array.from(arrayLike as any);
+ const result = arrReverse(arr);
+
+ assert.equal(result[0], "c");
+ assert.equal(result[1], "b");
+ assert.equal(result[2], "a");
+ });
+
+ it("should reverse array of strings", () => {
+ const result = arrReverse(["h", "e", "l", "l", "o"]);
+ assert.deepEqual(result, ["o", "l", "l", "e", "h"]);
+ });
+
+ it("should match native Array.prototype.reverse", () => {
+ const arr1 = [1, 2, 3, 4, 5];
+ const arr2 = [1, 2, 3, 4, 5];
+
+ arrReverse(arr1);
+ arr2.reverse();
+
+ assert.deepEqual(arr1, arr2);
+ });
+});
diff --git a/lib/test/src/common/array/rotate.test.ts b/lib/test/src/common/array/rotate.test.ts
new file mode 100644
index 00000000..5b83c97f
--- /dev/null
+++ b/lib/test/src/common/array/rotate.test.ts
@@ -0,0 +1,62 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { arrRotate } from "../../../../src/array/rotate";
+
+describe("arrRotate", () => {
+ it("should rotate array left by default", () => {
+ assert.deepEqual(arrRotate([1, 2, 3, 4, 5], 1), [2, 3, 4, 5, 1]);
+ assert.deepEqual(arrRotate([1, 2, 3, 4, 5], 2), [3, 4, 5, 1, 2]);
+ });
+
+ it("should rotate array right with negative positions", () => {
+ assert.deepEqual(arrRotate([1, 2, 3, 4, 5], -1), [5, 1, 2, 3, 4]);
+ assert.deepEqual(arrRotate([1, 2, 3, 4, 5], -2), [4, 5, 1, 2, 3]);
+ });
+
+ it("should handle rotation by length", () => {
+ assert.deepEqual(arrRotate([1, 2, 3], 3), [1, 2, 3]);
+ assert.deepEqual(arrRotate([1, 2, 3], -3), [1, 2, 3]);
+ });
+
+ it("should handle rotation greater than length", () => {
+ assert.deepEqual(arrRotate([1, 2, 3], 4), [2, 3, 1]);
+ assert.deepEqual(arrRotate([1, 2, 3], -4), [3, 1, 2]);
+ });
+
+ it("should handle zero rotation", () => {
+ assert.deepEqual(arrRotate([1, 2, 3], 0), [1, 2, 3]);
+ });
+
+ it("should handle empty array", () => {
+ assert.deepEqual(arrRotate([], 5), []);
+ });
+
+ it("should handle single element array", () => {
+ assert.deepEqual(arrRotate([1], 5), [1]);
+ });
+
+ it("should handle null and undefined", () => {
+ assert.deepEqual(arrRotate(null, 2), []);
+ assert.deepEqual(arrRotate(undefined, 2), []);
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 4, 0: "a", 1: "b", 2: "c", 3: "d" };
+ assert.deepEqual(arrRotate(arrayLike, 1), ["b", "c", "d", "a"]);
+ });
+
+ it("should not modify original array", () => {
+ const original = [1, 2, 3, 4];
+ const copy = [...original];
+ arrRotate(original, 2);
+
+ assert.deepEqual(original, copy);
+ });
+});
diff --git a/lib/test/src/common/array/shuffle_sample.test.ts b/lib/test/src/common/array/shuffle_sample.test.ts
new file mode 100644
index 00000000..39bf2fd8
--- /dev/null
+++ b/lib/test/src/common/array/shuffle_sample.test.ts
@@ -0,0 +1,113 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { arrShuffle } from "../../../../src/array/shuffle";
+import { arrSample } from "../../../../src/array/sample";
+
+describe("arrShuffle", () => {
+ it("should return array with same elements", () => {
+ const original = [1, 2, 3, 4, 5];
+ const shuffled = arrShuffle(original);
+
+ assert.equal(shuffled.length, original.length);
+ original.forEach(val => {
+ assert.ok(shuffled.includes(val), `Should contain ${val}`);
+ });
+ });
+
+ it("should not modify original array", () => {
+ const original = [1, 2, 3, 4, 5];
+ const copy = [...original];
+ arrShuffle(original);
+
+ assert.deepEqual(original, copy);
+ });
+
+ it("should handle single element array", () => {
+ assert.deepEqual(arrShuffle([1]), [1]);
+ });
+
+ it("should handle empty array", () => {
+ assert.deepEqual(arrShuffle([]), []);
+ });
+
+ it("should throw for null and undefined", () => {
+ // arrSlice (used internally) throws TypeError for null/undefined
+ assert.throws(() => arrShuffle(null));
+ assert.throws(() => arrShuffle(undefined));
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 3, 0: "x", 1: "y", 2: "z" };
+ const shuffled = arrShuffle(arrayLike);
+
+ assert.equal(shuffled.length, 3);
+ assert.ok(shuffled.includes("x"));
+ assert.ok(shuffled.includes("y"));
+ assert.ok(shuffled.includes("z"));
+ });
+
+ it("should produce different results (statistical)", () => {
+ const original = [1, 2, 3, 4, 5];
+ let different = false;
+
+ // Try multiple times - should be different at least once
+ for (let i = 0; i < 10; i++) {
+ const shuffled = arrShuffle(original);
+ if (JSON.stringify(shuffled) !== JSON.stringify(original)) {
+ different = true;
+ break;
+ }
+ }
+
+ assert.ok(different, "Should produce different ordering");
+ });
+});
+
+describe("arrSample", () => {
+ it("should return element from array", () => {
+ const arr = [1, 2, 3, 4, 5];
+ const sample = arrSample(arr);
+
+ assert.ok(arr.includes(sample), "Sample should be from array");
+ });
+
+ it("should return single element for single item array", () => {
+ assert.equal(arrSample([42]), 42);
+ });
+
+ it("should return undefined for empty array", () => {
+ assert.isUndefined(arrSample([]));
+ });
+
+ it("should throw for null and undefined", () => {
+ // arrSample expects a valid array
+ assert.isUndefined(arrSample(null));
+ assert.isUndefined(arrSample(undefined));
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 3, 0: "x", 1: "y", 2: "z" };
+ const sample = arrSample(arrayLike);
+
+ assert.ok(["x", "y", "z"].includes(sample));
+ });
+
+ it("should return different values (statistical)", () => {
+ const arr = [1, 2, 3, 4, 5];
+ const samples = new Set();
+
+ // Sample many times - should get different values
+ for (let i = 0; i < 50; i++) {
+ samples.add(arrSample(arr));
+ }
+
+ assert.ok(samples.size > 1, "Should sample different values");
+ });
+});
diff --git a/lib/test/src/common/array/take_drop.test.ts b/lib/test/src/common/array/take_drop.test.ts
new file mode 100644
index 00000000..775d1f13
--- /dev/null
+++ b/lib/test/src/common/array/take_drop.test.ts
@@ -0,0 +1,141 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { arrTake } from "../../../../src/array/take";
+import { arrDrop } from "../../../../src/array/drop";
+import { arrTakeWhile } from "../../../../src/array/take_while";
+import { arrDropWhile } from "../../../../src/array/drop_while";
+
+describe("arrTake", () => {
+ it("should take first n elements", () => {
+ assert.deepEqual(arrTake([1, 2, 3, 4, 5], 3), [1, 2, 3]);
+ assert.deepEqual(arrTake(["a", "b", "c"], 2), ["a", "b"]);
+ });
+
+ it("should return all elements when n exceeds length", () => {
+ assert.deepEqual(arrTake([1, 2], 5), [1, 2]);
+ });
+
+ it("should return empty array when n is 0 or negative", () => {
+ assert.deepEqual(arrTake([1, 2, 3], 0), []);
+ assert.deepEqual(arrTake([1, 2, 3], -1), []);
+ });
+
+ it("should throw for null and undefined", () => {
+ // arrSlice (used internally) throws TypeError for null/undefined
+ assert.throws(() => arrTake(null, 2));
+ assert.throws(() => arrTake(undefined, 2));
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 4, 0: 1, 1: 2, 2: 3, 3: 4 };
+ assert.deepEqual(arrTake(arrayLike, 2), [1, 2]);
+ });
+});
+
+describe("arrDrop", () => {
+ it("should drop first n elements", () => {
+ assert.deepEqual(arrDrop([1, 2, 3, 4, 5], 2), [3, 4, 5]);
+ assert.deepEqual(arrDrop(["a", "b", "c"], 1), ["b", "c"]);
+ });
+
+ it("should return empty array when n exceeds length", () => {
+ assert.deepEqual(arrDrop([1, 2], 5), []);
+ });
+
+ it("should return all elements when n is 0 or negative", () => {
+ assert.deepEqual(arrDrop([1, 2, 3], 0), [1, 2, 3]);
+ assert.deepEqual(arrDrop([1, 2, 3], -1), [1, 2, 3]);
+ });
+
+ it("should throw for null and undefined", () => {
+ // arrSlice (used internally) throws TypeError for null/undefined
+ assert.throws(() => arrDrop(null, 2));
+ assert.throws(() => arrDrop(undefined, 2));
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 4, 0: 1, 1: 2, 2: 3, 3: 4 };
+ assert.deepEqual(arrDrop(arrayLike, 2), [3, 4]);
+ });
+});
+
+describe("arrTakeWhile", () => {
+ it("should take elements while predicate is true", () => {
+ assert.deepEqual(arrTakeWhile([1, 2, 3, 4, 1], x => x < 3), [1, 2]);
+ assert.deepEqual(arrTakeWhile([2, 4, 6, 1, 8], x => x % 2 === 0), [2, 4, 6]);
+ });
+
+ it("should return empty array when first element fails predicate", () => {
+ assert.deepEqual(arrTakeWhile([1, 2, 3], x => x > 5), []);
+ });
+
+ it("should return all elements when all match predicate", () => {
+ assert.deepEqual(arrTakeWhile([1, 2, 3], x => x < 5), [1, 2, 3]);
+ });
+
+ it("should handle empty array", () => {
+ assert.deepEqual(arrTakeWhile([], x => x > 0), []);
+ });
+
+ it("should handle null and undefined", () => {
+ assert.deepEqual(arrTakeWhile(null, x => x > 0), []);
+ assert.deepEqual(arrTakeWhile(undefined, x => x > 0), []);
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 4, 0: 1, 1: 2, 2: 3, 3: 4 };
+ assert.deepEqual(arrTakeWhile(arrayLike, x => x < 3), [1, 2]);
+ });
+
+ it("should support thisArg", () => {
+ const threshold = { value: 3 };
+ const result = arrTakeWhile([1, 2, 3, 4, 5], function(x) {
+ return x < this.value;
+ }, threshold);
+ assert.deepEqual(result, [1, 2]);
+ });
+});
+
+describe("arrDropWhile", () => {
+ it("should drop elements while predicate is true", () => {
+ assert.deepEqual(arrDropWhile([1, 2, 3, 4, 1], x => x < 3), [3, 4, 1]);
+ assert.deepEqual(arrDropWhile([2, 4, 6, 1, 8], x => x % 2 === 0), [1, 8]);
+ });
+
+ it("should return all elements when first element fails predicate", () => {
+ assert.deepEqual(arrDropWhile([1, 2, 3], x => x > 5), [1, 2, 3]);
+ });
+
+ it("should return empty array when all match predicate", () => {
+ assert.deepEqual(arrDropWhile([1, 2, 3], x => x < 5), []);
+ });
+
+ it("should handle empty array", () => {
+ assert.deepEqual(arrDropWhile([], x => x > 0), []);
+ });
+
+ it("should handle null and undefined", () => {
+ assert.deepEqual(arrDropWhile(null, x => x > 0), []);
+ assert.deepEqual(arrDropWhile(undefined, x => x > 0), []);
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 4, 0: 1, 1: 2, 2: 3, 3: 4 };
+ assert.deepEqual(arrDropWhile(arrayLike, x => x < 3), [3, 4]);
+ });
+
+ it("should support thisArg", () => {
+ const threshold = { value: 3 };
+ const result = arrDropWhile([1, 2, 3, 4, 5], function(x) {
+ return x < this.value;
+ }, threshold);
+ assert.deepEqual(result, [3, 4, 5]);
+ });
+});
diff --git a/lib/test/src/common/array/union.test.ts b/lib/test/src/common/array/union.test.ts
new file mode 100644
index 00000000..b6751c97
--- /dev/null
+++ b/lib/test/src/common/array/union.test.ts
@@ -0,0 +1,48 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { arrUnion } from "../../../../src/array/union";
+
+describe("arrUnion", () => {
+ it("should return unique elements from two arrays", () => {
+ assert.deepEqual(arrUnion([1, 2], [2, 3]), [1, 2, 3]);
+ assert.deepEqual(arrUnion(["a", "b"], ["b", "c"]), ["a", "b", "c"]);
+ });
+
+ it("should handle multiple arrays", () => {
+ assert.deepEqual(arrUnion([1, 2], [3, 4], [4, 5]), [1, 2, 3, 4, 5]);
+ });
+
+ it("should remove duplicates", () => {
+ assert.deepEqual(arrUnion([1, 1, 2], [2, 2, 3]), [1, 2, 3]);
+ });
+
+ it("should handle empty arrays", () => {
+ assert.deepEqual(arrUnion([], [1, 2]), [1, 2]);
+ assert.deepEqual(arrUnion([1, 2], []), [1, 2]);
+ assert.deepEqual(arrUnion([], []), []);
+ });
+
+ it("should handle single array", () => {
+ assert.deepEqual(arrUnion([1, 2, 3]), [1, 2, 3]);
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 2, 0: 1, 1: 2 };
+ assert.deepEqual(arrUnion(arrayLike, [2, 3]), [1, 2, 3]);
+ });
+
+ it("should use strict equality", () => {
+ assert.deepEqual(arrUnion([1, 2], ["1", "2"]), [1, 2, "1", "2"]);
+ });
+
+ it("should preserve insertion order", () => {
+ assert.deepEqual(arrUnion([3, 1], [2, 4]), [3, 1, 2, 4]);
+ });
+});
diff --git a/lib/test/src/common/array/with.test.ts b/lib/test/src/common/array/with.test.ts
new file mode 100644
index 00000000..ef5f7eb7
--- /dev/null
+++ b/lib/test/src/common/array/with.test.ts
@@ -0,0 +1,184 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { arrWith, polyArrWith } from "../../../../src/array/with";
+
+describe("arrWith", () => {
+ it("should return new array with element replaced", () => {
+ const arr = [1, 2, 3];
+ const result = arrWith(arr, 1, 99);
+
+ assert.deepEqual(result, [1, 99, 3]);
+ assert.deepEqual(arr, [1, 2, 3]); // Original unchanged
+ });
+
+ it("should handle negative indices", () => {
+ const arr = [1, 2, 3, 4, 5];
+ assert.deepEqual(arrWith(arr, -1, 99), [1, 2, 3, 4, 99]);
+ assert.deepEqual(arrWith(arr, -2, 88), [1, 2, 3, 88, 5]);
+ });
+
+ it("should throw RangeError for out of bounds positive index", () => {
+ assert.throws(() => arrWith([1, 2, 3], 5, 99), RangeError);
+ assert.throws(() => arrWith([1, 2, 3], 3, 99), RangeError);
+ assert.throws(() => arrWith([1, 2, 3], 100, 0), RangeError);
+ });
+
+ it("should throw RangeError for out of bounds negative index", () => {
+ assert.throws(() => arrWith([1, 2, 3], -4, 99), RangeError);
+ assert.throws(() => arrWith([1, 2, 3], -10, 99), RangeError);
+ assert.throws(() => arrWith([1, 2, 3], -100, 0), RangeError);
+ });
+
+ it("should throw RangeError for empty array", () => {
+ assert.throws(() => arrWith([], 0, 99), RangeError);
+ assert.throws(() => arrWith([], -1, 99), RangeError);
+ });
+
+ it("should replace last element with -1", () => {
+ assert.deepEqual(arrWith([10, 20, 30], -1, 99), [10, 20, 99]);
+ });
+
+ it("should replace first element with -length", () => {
+ assert.deepEqual(arrWith([10, 20, 30], -3, 99), [99, 20, 30]);
+ });
+
+ it("should throw when index equals length", () => {
+ const arr = [1, 2, 3];
+ assert.throws(() => arrWith(arr, arr.length, 99), RangeError);
+ });
+
+ it("should throw when negative index points beyond start", () => {
+ const arr = [1, 2, 3];
+ assert.throws(() => arrWith(arr, -(arr.length + 1), 99), RangeError);
+ });
+
+ it("should handle index 0", () => {
+ assert.deepEqual(arrWith([1, 2, 3], 0, 99), [99, 2, 3]);
+ });
+
+ it("should throw for null and undefined array", () => {
+ // Native .with() throws TypeError for null/undefined
+ assert.throws(() => arrWith(null, 0, 99));
+ assert.throws(() => arrWith(undefined, 0, 99));
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 3, 0: "a", 1: "b", 2: "c" };
+ assert.deepEqual(arrWith(arrayLike, 1, "x"), ["a", "x", "c"]);
+ });
+
+ it("should not modify original array", () => {
+ const original = [1, 2, 3];
+ const copy = [...original];
+ arrWith(original, 1, 99);
+
+ assert.deepEqual(original, copy);
+ });
+});
+
+describe("polyArrWith", () => {
+ it("should match native Array.prototype.with for valid indices", () => {
+ const arr: any = [1, 2, 3, 4, 5];
+
+ for (let i = 0; i < arr.length; i++) {
+ const polyResult = polyArrWith(arr, i, 99);
+
+ if (arr.with) {
+ const nativeResult = arr.with(i, 99);
+ assert.deepEqual(polyResult, nativeResult, `Index ${i} should match`);
+ } else {
+ const expected = [...arr];
+ expected[i] = 99;
+ assert.deepEqual(polyResult, expected);
+ }
+ }
+ });
+
+ it("should match native Array.prototype.with for negative indices", () => {
+ const arr: any = [1, 2, 3, 4, 5];
+
+ for (let i = -1; i >= -arr.length; i--) {
+ const polyResult = polyArrWith(arr, i, 99);
+
+ if (arr.with) {
+ const nativeResult = arr.with(i, 99);
+ assert.deepEqual(polyResult, nativeResult, `Index ${i} should match`);
+ } else {
+ const expected = [...arr];
+ expected[arr.length + i] = 99;
+ assert.deepEqual(polyResult, expected);
+ }
+ }
+ });
+
+ it("should throw RangeError for out of bounds like native", () => {
+ const arr: any = [1, 2, 3];
+
+ assert.throws(() => polyArrWith(arr, 5, 99), RangeError);
+ assert.throws(() => polyArrWith(arr, -10, 99), RangeError);
+ assert.throws(() => polyArrWith(arr, 3, 0), RangeError); // Index at length
+ assert.throws(() => polyArrWith(arr, -4, 0), RangeError); // Negative index beyond start
+
+ if (arr.with) {
+ assert.throws(() => arr.with(5, 99), RangeError);
+ assert.throws(() => arr.with(-10, 99), RangeError);
+ }
+ });
+
+ it("should throw RangeError for empty array-like objects", () => {
+ const emptyArrayLike = { length: 0 };
+ assert.throws(() => polyArrWith(emptyArrayLike, 0, 99), RangeError);
+ assert.throws(() => polyArrWith(emptyArrayLike, -1, 99), RangeError);
+ });
+
+ it("should handle boundary indices correctly", () => {
+ const arr = [10, 20, 30];
+
+ // Valid: index 0 to length-1
+ assert.deepEqual(polyArrWith(arr, 0, 1), [1, 20, 30]);
+ assert.deepEqual(polyArrWith(arr, 1, 2), [10, 2, 30]);
+ assert.deepEqual(polyArrWith(arr, 2, 3), [10, 20, 3]);
+
+ // Valid: negative indices from -1 to -length
+ assert.deepEqual(polyArrWith(arr, -1, 1), [10, 20, 1]);
+ assert.deepEqual(polyArrWith(arr, -2, 2), [10, 2, 30]);
+ assert.deepEqual(polyArrWith(arr, -3, 3), [3, 20, 30]);
+ });
+
+ it("should not modify original array like native", () => {
+ const arr: any = [1, 2, 3];
+ const copy = [...arr];
+
+ polyArrWith(arr, 1, 99);
+ assert.deepEqual(arr, copy);
+
+ if (arr.with) {
+ arr.with(1, 99);
+ assert.deepEqual(arr, copy);
+ }
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 3, 0: 10, 1: 20, 2: 30 };
+ const result = polyArrWith(arrayLike, 1, 99);
+
+ assert.deepEqual(result, [10, 99, 30]);
+ });
+
+ it("should handle empty array correctly", () => {
+ const arr: number[] = [];
+
+ assert.throws(() => polyArrWith(arr, 0, 99), RangeError);
+
+ if ((arr as any).with) {
+ assert.throws(() => (arr as any).with(0, 99), RangeError);
+ }
+ });
+});
diff --git a/lib/test/src/common/array/zip_unzip.test.ts b/lib/test/src/common/array/zip_unzip.test.ts
new file mode 100644
index 00000000..d7d412a7
--- /dev/null
+++ b/lib/test/src/common/array/zip_unzip.test.ts
@@ -0,0 +1,96 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { arrZip } from "../../../../src/array/zip";
+import { arrUnzip } from "../../../../src/array/unzip";
+
+describe("arrZip", () => {
+ it("should combine arrays by index", () => {
+ assert.deepEqual(arrZip([1, 2], ["a", "b"]), [[1, "a"], [2, "b"]]);
+ assert.deepEqual(arrZip([1, 2, 3], ["a", "b", "c"]), [[1, "a"], [2, "b"], [3, "c"]]);
+ });
+
+ it("should handle arrays of different lengths", () => {
+ const result = arrZip([1, 2, 3], ["a", "b"]);
+ assert.equal(result.length, 2);
+ assert.deepEqual(result, [[1, "a"], [2, "b"]]);
+ });
+
+ it("should handle three or more arrays", () => {
+ assert.deepEqual(
+ arrZip([1, 2], ["a", "b"], [true, false]),
+ [[1, "a", true], [2, "b", false]]
+ );
+ });
+
+ it("should handle single array", () => {
+ assert.deepEqual(arrZip([1, 2, 3]), [[1], [2], [3]]);
+ });
+
+ it("should return empty array when empty arrays provided", () => {
+ assert.deepEqual(arrZip([], []), []);
+ });
+
+ it("should handle null and undefined", () => {
+ assert.deepEqual(arrZip(null), []);
+ assert.deepEqual(arrZip(undefined), []);
+ assert.deepEqual(arrZip([1, 2], null), [[1], [2]]);
+ });
+
+ it("should work with array-like objects", () => {
+ const arrayLike = { length: 2, 0: 1, 1: 2 };
+ assert.deepEqual(arrZip(arrayLike, ["a", "b"]), [[1, "a"], [2, "b"]]);
+ });
+});
+
+describe("arrUnzip", () => {
+ it("should reverse zip operation", () => {
+ const zipped = [[1, "a"], [2, "b"], [3, "c"]];
+ assert.deepEqual(arrUnzip(zipped), [[1, 2, 3], ["a", "b", "c"]]);
+ });
+
+ it("should handle arrays with more than 2 elements", () => {
+ const zipped = [[1, "a", true], [2, "b", false]];
+ assert.deepEqual(arrUnzip(zipped), [[1, 2], ["a", "b"], [true, false]]);
+ });
+
+ it("should handle irregular arrays", () => {
+ const irregular = [[1, "a"], [2], [3, "c", true]];
+ const result = arrUnzip(irregular);
+ assert.equal(result[0][0], 1);
+ assert.equal(result[0][1], 2);
+ assert.equal(result[0][2], 3);
+ assert.equal(result[1][0], "a");
+ assert.isUndefined(result[1][1]);
+ assert.equal(result[1][2], "c");
+ });
+
+ it("should return empty array for empty array", () => {
+ assert.deepEqual(arrUnzip([]), []);
+ });
+
+ it("should handle null and undefined", () => {
+ assert.deepEqual(arrUnzip(null), []);
+ assert.deepEqual(arrUnzip(undefined), []);
+ });
+
+ it("should handle single element arrays", () => {
+ assert.deepEqual(arrUnzip([[1], [2], [3]]), [[1, 2, 3]]);
+ });
+
+ it("should be inverse of arrZip", () => {
+ const arr1 = [1, 2, 3];
+ const arr2 = ["a", "b", "c"];
+ const zipped = arrZip(arr1, arr2);
+ const unzipped = arrUnzip(zipped);
+
+ assert.deepEqual(unzipped[0], arr1);
+ assert.deepEqual(unzipped[1], arr2);
+ });
+});
diff --git a/lib/test/src/common/helpers/array.test.ts b/lib/test/src/common/helpers/array.test.ts
index 489f107e..707bf9a0 100644
--- a/lib/test/src/common/helpers/array.test.ts
+++ b/lib/test/src/common/helpers/array.test.ts
@@ -8,8 +8,12 @@
import { assert } from "@nevware21/tripwire-chai";
import { arrAppend } from "../../../../src/array/append";
+import { arrChunk } from "../../../../src/array/chunk";
+import { arrCompact } from "../../../../src/array/compact";
import { arrFind, arrFindIndex, arrFindLast, arrFindLastIndex } from "../../../../src/array/find";
+import { arrFlatten } from "../../../../src/array/flatten";
import { arrFrom } from "../../../../src/array/from";
+import { arrGroupBy } from "../../../../src/array/groupBy";
import { arrSome } from "../../../../src/array/some";
import { arrForEach } from "../../../../src/array/forEach";
import { arrContains, arrIncludes } from "../../../../src/array/includes";
@@ -18,6 +22,7 @@ import { arrEvery, arrFilter } from "../../../../src/array/every";
import { arrMap } from "../../../../src/array/map";
import { arrReduce } from "../../../../src/array/reduce";
import { arrSlice } from "../../../../src/array/slice";
+import { arrUnique } from "../../../../src/array/unique";
import { dumpObj } from "../../../../src/helpers/diagnostics";
describe("array helpers", () => {
@@ -973,6 +978,202 @@ describe("array helpers", () => {
});
});
+ describe("arrUnique", () => {
+ it("removes duplicate primitives", () => {
+ assert.deepEqual(arrUnique([1, 2, 2, 3, 1, 4]), [1, 2, 3, 4]);
+ assert.deepEqual(arrUnique(["a", "b", "a", "c"]), ["a", "b", "c"]);
+ assert.deepEqual(arrUnique([1, "1", 1, "1"]), [1, "1"]);
+ });
+
+ it("preserves insertion order", () => {
+ assert.deepEqual(arrUnique([3, 1, 2, 1, 3]), [3, 1, 2]);
+ assert.deepEqual(arrUnique(["z", "a", "z", "b"]), ["z", "a", "b"]);
+ });
+
+ it("handles empty and single element arrays", () => {
+ assert.deepEqual(arrUnique([]), []);
+ assert.deepEqual(arrUnique([1]), [1]);
+ });
+
+ it("handles null and undefined", () => {
+ assert.deepEqual(arrUnique(null), []);
+ assert.deepEqual(arrUnique(undefined), []);
+ });
+
+ it("handles array-like objects", () => {
+ assert.deepEqual(arrUnique({ length: 4, 0: 1, 1: 2, 2: 2, 3: 3 }), [1, 2, 3]);
+ assert.deepEqual(arrUnique({ length: 3, 0: "a", 1: "b", 2: "a" }), ["a", "b"]);
+ });
+
+ it("uses strict equality", () => {
+ assert.deepEqual(arrUnique([0, false, 0, false]), [0, false]);
+ assert.deepEqual(arrUnique([null, undefined, null]), [null, undefined]);
+ });
+ });
+
+ describe("arrCompact", () => {
+ it("removes falsy values", () => {
+ assert.deepEqual(arrCompact([0, 1, false, 2, "", 3, null, undefined, 4]), [1, 2, 3, 4]);
+ assert.deepEqual(arrCompact([false, 0, "", null, undefined]), []);
+ });
+
+ it("preserves truthy values", () => {
+ assert.deepEqual(arrCompact([1, 2, 3]), [1, 2, 3]);
+ assert.deepEqual(arrCompact(["a", "b", "c"]), ["a", "b", "c"]);
+ assert.deepEqual(arrCompact([true, true, true]), [true, true, true]);
+ });
+
+ it("handles empty arrays", () => {
+ assert.deepEqual(arrCompact([]), []);
+ });
+
+ it("handles null and undefined", () => {
+ assert.deepEqual(arrCompact(null), []);
+ assert.deepEqual(arrCompact(undefined), []);
+ });
+
+ it("handles array-like objects", () => {
+ assert.deepEqual(arrCompact({ length: 5, 0: 0, 1: 1, 2: false, 3: 2, 4: null }), [1, 2]);
+ assert.deepEqual(arrCompact({ length: 3, 0: "a", 1: "", 2: "b" }), ["a", "b"]);
+ });
+
+ it("preserves numbers and strings properly", () => {
+ assert.deepEqual(arrCompact([1, 0, 2]), [1, 2]);
+ assert.deepEqual(arrCompact(["hello", "", "world"]), ["hello", "world"]);
+ });
+ });
+
+ describe("arrFlatten", () => {
+ it("flattens with default depth of 1", () => {
+ assert.deepEqual(arrFlatten([1, [2, 3], [4, [5, 6]]]), [1, 2, 3, 4, [5, 6]]);
+ assert.deepEqual(arrFlatten([1, [2], 3]), [1, 2, 3]);
+ });
+
+ it("flattens with specified depth", () => {
+ assert.deepEqual(arrFlatten([1, [2, 3], [4, [5, 6]]], 2), [1, 2, 3, 4, 5, 6]);
+ assert.deepEqual(arrFlatten([1, [2, [3, [4]]]], 2), [1, 2, 3, [4]]);
+ });
+
+ it("flattens with infinite depth", () => {
+ assert.deepEqual(arrFlatten([1, [2, 3], [4, [5, 6]]], Infinity), [1, 2, 3, 4, 5, 6]);
+ assert.deepEqual(arrFlatten([1, [2, [3, [4, [5]]]]], Infinity), [1, 2, 3, 4, 5]);
+ });
+
+ it("handles non-arrays when depth is 0", () => {
+ assert.deepEqual(arrFlatten([1, [2, 3]], 0), [1, [2, 3]]);
+ });
+
+ it("preserves non-nested arrays", () => {
+ assert.deepEqual(arrFlatten([1, 2, 3]), [1, 2, 3]);
+ });
+
+ it("handles empty arrays", () => {
+ assert.deepEqual(arrFlatten([]), []);
+ });
+
+ it("handles null and undefined", () => {
+ assert.deepEqual(arrFlatten(null), []);
+ assert.deepEqual(arrFlatten(undefined), []);
+ });
+
+ it("handles array-like objects", () => {
+ assert.deepEqual(arrFlatten({ length: 2, 0: 1, 1: [2, 3] }), [1, 2, 3]);
+ });
+ });
+
+ describe("arrGroupBy", () => {
+ it("groups by simple criteria", () => {
+ const numbers = [1, 2, 3, 4, 5, 6];
+ const grouped = arrGroupBy(numbers, (n) => n % 2 === 0 ? "even" : "odd");
+ assert.deepEqual(grouped["odd"], [1, 3, 5]);
+ assert.deepEqual(grouped["even"], [2, 4, 6]);
+ });
+
+ it("groups objects by property", () => {
+ const people = [
+ { name: "Alice", age: 30 },
+ { name: "Bob", age: 25 },
+ { name: "Charlie", age: 30 }
+ ];
+ const byAge = arrGroupBy(people, (p) => p.age);
+ assert.equal(byAge["25"].length, 1);
+ assert.equal(byAge["30"].length, 2);
+ assert.equal(byAge["25"][0].name, "Bob");
+ });
+
+ it("handles empty arrays", () => {
+ const grouped = arrGroupBy([], (x) => x);
+ assert.deepEqual(grouped, {});
+ });
+
+ it("handles null and undefined input", () => {
+ assert.deepEqual(arrGroupBy(null as any, (x: any) => x), {});
+ assert.deepEqual(arrGroupBy(undefined as any, (x: any) => x), {});
+ });
+
+ it("handles null callback", () => {
+ assert.deepEqual(arrGroupBy([1, 2, 3], null as any), {});
+ });
+
+ it("supports thisArg parameter", () => {
+ const context = { multiplier: 2 };
+ const numbers = [1, 2, 3, 4];
+ const grouped = arrGroupBy(numbers, function(n) {
+ return (n * (this as any).multiplier) % 2 === 0 ? "even" : "odd";
+ }, context);
+ assert.ok(grouped["odd"] || grouped["even"]);
+ });
+
+ it("handles array-like objects", () => {
+ const arrayLike = { length: 4, 0: 1, 1: 2, 2: 3, 3: 4 };
+ const grouped = arrGroupBy(arrayLike, (n) => n % 2 === 0 ? "even" : "odd");
+ assert.equal(grouped["odd"].length, 2);
+ assert.equal(grouped["even"].length, 2);
+ });
+ });
+
+ describe("arrChunk", () => {
+ it("chunks array into specified size", () => {
+ assert.deepEqual(arrChunk([1, 2, 3, 4, 5, 6, 7], 2), [[1, 2], [3, 4], [5, 6], [7]]);
+ assert.deepEqual(arrChunk([1, 2, 3, 4, 5], 3), [[1, 2, 3], [4, 5]]);
+ });
+
+ it("handles chunk size of 1", () => {
+ assert.deepEqual(arrChunk([1, 2, 3], 1), [[1], [2], [3]]);
+ });
+
+ it("handles chunk size larger than array", () => {
+ assert.deepEqual(arrChunk([1, 2, 3], 5), [[1, 2, 3]]);
+ });
+
+ it("handles empty arrays", () => {
+ assert.deepEqual(arrChunk([], 2), []);
+ });
+
+ it("handles null and undefined", () => {
+ assert.deepEqual(arrChunk(null, 2), []);
+ assert.deepEqual(arrChunk(undefined, 2), []);
+ });
+
+ it("handles invalid chunk size", () => {
+ assert.deepEqual(arrChunk([1, 2, 3], 0), []);
+ assert.deepEqual(arrChunk([1, 2, 3], -1), []);
+ });
+
+ it("handles array-like objects", () => {
+ const arrayLike = { length: 5, 0: "a", 1: "b", 2: "c", 3: "d", 4: "e" };
+ assert.deepEqual(arrChunk(arrayLike, 2), [["a", "b"], ["c", "d"], ["e"]]);
+ });
+
+ it("preserves exact chunk boundaries", () => {
+ const data = [10, 20, 30, 40, 50, 60];
+ const chunks = arrChunk(data, 3);
+ assert.equal(chunks.length, 2);
+ assert.deepEqual(chunks[0], [10, 20, 30]);
+ assert.deepEqual(chunks[1], [40, 50, 60]);
+ });
+ });
+
function _expectThrow(cb: () => void): Error {
try {
cb();
diff --git a/lib/test/src/common/helpers/base.test.ts b/lib/test/src/common/helpers/base.test.ts
index 3a330331..fcf94efc 100644
--- a/lib/test/src/common/helpers/base.test.ts
+++ b/lib/test/src/common/helpers/base.test.ts
@@ -8,7 +8,7 @@
import { assert } from "@nevware21/tripwire-chai";
import {
- isArray, isBoolean, isDate, isDefined, isFunction, isNullOrUndefined, isNumber, isObject, isString, isTypeof,
+ isArray, isArrayLike, isBoolean, isDate, isDefined, isFunction, isNullOrUndefined, isNumber, isObject, isString, isTypeof,
isUndefined, isRegExp, isFile, isFormData, isBlob, isArrayBuffer, isError, isPromiseLike, isPromise, isNotTruthy,
isTruthy, isStrictUndefined, isStrictNullOrUndefined, isPrimitive, isPrimitiveType, isMap
} from "../../../../src/helpers/base";
@@ -639,6 +639,75 @@ describe("base helpers", () => {
});
});
+ describe("isArrayLike", () => {
+ it("Validate values", () => {
+ assert.equal(isArrayLike(null), false, "Checking null");
+ assert.equal(isArrayLike(undefined), false, "Checking undefined");
+ assert.equal(isArrayLike("null"), true, "Checking 'null' (strings are array-like)");
+ assert.equal(isArrayLike("undefined"), true, "Checking 'undefined' (strings are array-like)");
+ assert.equal(isArrayLike("hello"), true, "Checking 'hello' (strings are array-like)");
+ assert.equal(isArrayLike(""), true, "Checking '' (empty string is array-like)");
+ assert.equal(isArrayLike(new Date()), false, "Checking Date");
+ assert.equal(isArrayLike(1), false, "Checking 1");
+ assert.equal(isArrayLike(0), false, "Checking 0");
+ assert.equal(isArrayLike(_dummyFunction), false, "Checking _dummyFunction");
+ assert.equal(isArrayLike([]), true, "Checking []");
+ assert.equal(isArrayLike([1, 2, 3]), true, "Checking [1, 2, 3]");
+ assert.equal(isArrayLike(new Array(1)), true, "Checking new Array(1)");
+ assert.equal(isArrayLike(true), false, "Checking true");
+ assert.equal(isArrayLike(false), false, "Checking false");
+ assert.equal(isArrayLike("true"), true, "Checking 'true'");
+ assert.equal(isArrayLike("false"), true, "Checking 'false'");
+ assert.equal(isArrayLike(new Boolean(true)), false, "Checking new Boolean(true)");
+ assert.equal(isArrayLike(new Boolean(false)), false, "Checking new Boolean(false)");
+ assert.equal(isArrayLike(new Boolean("true")), false, "Checking new Boolean('true')");
+ assert.equal(isArrayLike(new Boolean("false")), false, "Checking new Boolean('false')");
+ assert.equal(isArrayLike(/[a-z]/g), false, "Checking '/[a-z]/g'");
+ assert.equal(isArrayLike(new RegExp("")), false, "Checking new RegExp('')");
+ _isFileCheck(isArrayLike, false);
+ _isFormDataCheck(isArrayLike, false);
+ _isBlobCheck(isArrayLike, false);
+ assert.equal(isArrayLike(new ArrayBuffer(0)), false, "Checking new ArrayBuffer([])");
+ assert.equal(isArrayLike(new Error("Test Error")), false, "Checking new Error('')");
+ assert.equal(isArrayLike(new TypeError("Test TypeError")), false, "Checking new TypeError('')");
+ assert.equal(isArrayLike(new TestError("Test TestError")), false, "Checking new TestError('')");
+ assert.equal(isArrayLike(_dummyError()), false, "Checking dummy error (object that looks like an error)");
+ assert.equal(isArrayLike(Promise.reject()), false, "Checking Promise.reject");
+ assert.equal(isArrayLike(Promise.resolve()), false, "Checking Promise.resolve");
+ assert.equal(isArrayLike(new Promise(() => {})), false, "Checking new Promise(() => {})");
+ assert.equal(isArrayLike(_simplePromise()), false, "Checking _simplePromise");
+ assert.equal(isArrayLike(_simplePromiseLike()), false, "Checking _simplePromiseLike");
+ assert.equal(isArrayLike(Object.create(null)), false, "Checking Object.create(null)");
+ assert.equal(isArrayLike(polyObjCreate(null)), false, "Checking polyObjCreate(null)");
+ });
+
+ it("Validate array-like objects", () => {
+ // Object with length property
+ const arrayLike = { length: 3, 0: "a", 1: "b", 2: "c" };
+ assert.equal(isArrayLike(arrayLike), true, "Checking array-like object");
+
+ // Object with length but no numeric indices
+ const hasLength = { length: 5 };
+ assert.equal(isArrayLike(hasLength), true, "Checking object with length property");
+
+ // Object with length but it's not a number
+ const lengthNotNumber = { length: "3" };
+ assert.equal(isArrayLike(lengthNotNumber), false, "Checking object with non-numeric length");
+
+ // Object with no length property
+ const noLength = { 0: "a", 1: "b" };
+ assert.equal(isArrayLike(noLength), false, "Checking object with numeric indices but no length");
+
+ // Object with negative length
+ const negativeLength = { length: -1 };
+ assert.equal(isArrayLike(negativeLength), false, "Checking object with negative length");
+
+ // Object with length 0
+ const emptyLength = { length: 0 };
+ assert.equal(isArrayLike(emptyLength), true, "Checking object with length 0");
+ });
+ });
+
describe("isDate", () => {
it("Validate values", () => {
assert.equal(isDate(null), false, "Checking null");