diff --git a/.size-limit.json b/.size-limit.json
index 2b4cbd53..c322291b 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": "35 kb",
+ "limit": "37 kb",
"brotli": false,
"running": false
},
{
"name": "es6-full",
"path": "lib/dist/es6/mod/ts-utils.js",
- "limit": "33.5 kb",
+ "limit": "35.5 kb",
"brotli": false,
"running": false
},
{
"name": "es5-full-brotli",
"path": "lib/dist/es5/mod/ts-utils.js",
- "limit": "12.5 kb",
+ "limit": "12.75 kb",
"brotli": true,
"running": false
},
{
"name": "es6-full-brotli",
"path": "lib/dist/es6/mod/ts-utils.js",
- "limit": "12 kb",
+ "limit": "12.5 kb",
"brotli": true,
"running": false
},
{
"name": "es5-zip",
"path": "lib/dist/es5/mod/ts-utils.js",
- "limit": "13.5 Kb",
+ "limit": "14 Kb",
"gzip": true,
"running": false
},
{
"name": "es6-zip",
"path": "lib/dist/es6/mod/ts-utils.js",
- "limit": "13.5 Kb",
+ "limit": "14 Kb",
"gzip": true,
"running": false
},
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ce925039..f28afe71 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,11 @@
- Adds shared queue logic and callback-argument support across microtask and nextTick scheduling
- Adds `arrConcat` as a dedicated array helper and `fnBindArgs` as a dedicated function helper
- Improves function binding typing with exported `BoundFunction` and updated signatures for `fnBind` / `fnBindArgs`
+- [#574](https://github.com/nevware21/ts-utils/pull/574) feat(iterator,array): add iterator collection helpers, split helper modules, and align collection membership semantics
+ - Added new iterator helpers: `iterMap`, `iterFilter`, `iterTake`, `iterReduce`, `iterSome`, `iterEvery`, `iterToArray`, `iterUnion`, `iterIntersection`, `iterDifference`
+ - Added `arrToMap` helper in the array module and moved callback/type declarations into `iterator/types`
+ - Refactored iterator helper implementation/tests into per-function files and updated root exports
+ - Added NaN regression coverage and switched iterator set-operation membership checks to `arrIncludes` semantics for parity with array helpers
### Bug Fixes
diff --git a/README.md b/README.md
index 03f8b8d8..b2d22672 100644
--- a/README.md
+++ b/README.md
@@ -127,7 +127,7 @@ Below is a categorized list of all available utilities with direct links to thei
| 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)();
| Function | [fnApply](https://nevware21.github.io/ts-utils/typedoc/functions/fnApply.html)(); [fnBind](https://nevware21.github.io/ts-utils/typedoc/functions/fnBind.html)(); [fnBindArgs](https://nevware21.github.io/ts-utils/typedoc/functions/fnBindArgs.html)(); [fnCall](https://nevware21.github.io/ts-utils/typedoc/functions/fnCall.html)(); [createFnDeferredProxy](https://nevware21.github.io/ts-utils/typedoc/functions/createFnDeferredProxy.html)(); [createProxyFuncs](https://nevware21.github.io/ts-utils/typedoc/functions/createProxyFuncs.html)(); [readArgs](https://nevware21.github.io/ts-utils/typedoc/functions/readArgs.html)();
| Idle | [getCancelIdleCallback](https://nevware21.github.io/ts-utils/typedoc/functions/getCancelIdleCallback.html)(); [getIdleCallback](https://nevware21.github.io/ts-utils/typedoc/functions/getIdleCallback.html)(); [hasIdleCallback](https://nevware21.github.io/ts-utils/typedoc/functions/hasIdleCallback.html)(); [setDefaultIdleTimeout](https://nevware21.github.io/ts-utils/typedoc/functions/setDefaultIdleTimeout.html)(); [setDefaultMaxExecutionTime](https://nevware21.github.io/ts-utils/typedoc/functions/setDefaultMaxExecutionTime.html)();
-| Iterator | [createArrayIterator](https://nevware21.github.io/ts-utils/typedoc/functions/createArrayIterator.html)(); [createIterator](https://nevware21.github.io/ts-utils/typedoc/functions/createIterator.html)(); [createIterable](https://nevware21.github.io/ts-utils/typedoc/functions/createIterable.html)(); [createRangeIterator](https://nevware21.github.io/ts-utils/typedoc/functions/createRangeIterator.html)(); [iterForOf](https://nevware21.github.io/ts-utils/typedoc/functions/iterForOf.html)(); [isAsyncIterable](https://nevware21.github.io/ts-utils/typedoc/functions/isAsyncIterable.html)(); [isIterable](https://nevware21.github.io/ts-utils/typedoc/functions/isIterable.html)(); [isIterator](https://nevware21.github.io/ts-utils/typedoc/functions/isIterator.html)(); [makeIterable](https://nevware21.github.io/ts-utils/typedoc/functions/makeIterable.html)(); [arrAppend](https://nevware21.github.io/ts-utils/typedoc/functions/arrAppend.html)(); [arrFrom](https://nevware21.github.io/ts-utils/typedoc/functions/arrFrom.html)();
+| Iterator | [createArrayIterator](https://nevware21.github.io/ts-utils/typedoc/functions/createArrayIterator.html)(); [createIterator](https://nevware21.github.io/ts-utils/typedoc/functions/createIterator.html)(); [createIterable](https://nevware21.github.io/ts-utils/typedoc/functions/createIterable.html)(); [createIterableIterator](https://nevware21.github.io/ts-utils/typedoc/functions/createIterableIterator.html)(); [createRangeIterator](https://nevware21.github.io/ts-utils/typedoc/functions/createRangeIterator.html)(); [iterForOf](https://nevware21.github.io/ts-utils/typedoc/functions/iterForOf.html)(); [iterMap](https://nevware21.github.io/ts-utils/typedoc/functions/iterMap.html)(); [iterFilter](https://nevware21.github.io/ts-utils/typedoc/functions/iterFilter.html)(); [iterTake](https://nevware21.github.io/ts-utils/typedoc/functions/iterTake.html)(); [iterReduce](https://nevware21.github.io/ts-utils/typedoc/functions/iterReduce.html)(); [iterSome](https://nevware21.github.io/ts-utils/typedoc/functions/iterSome.html)(); [iterEvery](https://nevware21.github.io/ts-utils/typedoc/functions/iterEvery.html)(); [iterToArray](https://nevware21.github.io/ts-utils/typedoc/functions/iterToArray.html)(); [iterUnion](https://nevware21.github.io/ts-utils/typedoc/functions/iterUnion.html)(); [iterIntersection](https://nevware21.github.io/ts-utils/typedoc/functions/iterIntersection.html)(); [iterDifference](https://nevware21.github.io/ts-utils/typedoc/functions/iterDifference.html)(); [isAsyncIterable](https://nevware21.github.io/ts-utils/typedoc/functions/isAsyncIterable.html)(); [isIterable](https://nevware21.github.io/ts-utils/typedoc/functions/isIterable.html)(); [isIterator](https://nevware21.github.io/ts-utils/typedoc/functions/isIterator.html)(); [makeIterable](https://nevware21.github.io/ts-utils/typedoc/functions/makeIterable.html)(); [arrAppend](https://nevware21.github.io/ts-utils/typedoc/functions/arrAppend.html)(); [arrFrom](https://nevware21.github.io/ts-utils/typedoc/functions/arrFrom.html)(); [arrToMap](https://nevware21.github.io/ts-utils/typedoc/functions/arrToMap.html)();
| Number | [getIntValue](https://nevware21.github.io/ts-utils/typedoc/functions/getIntValue.html)(); [isInteger](https://nevware21.github.io/ts-utils/typedoc/functions/isInteger.html)(); [isIntegerInRange](https://nevware21.github.io/ts-utils/typedoc/functions/isIntegerInRange.html)(); [isFiniteNumber](https://nevware21.github.io/ts-utils/typedoc/functions/isFiniteNumber.html)(); [isNumber](https://nevware21.github.io/ts-utils/typedoc/functions/isNumber.html)();
| Math | [mathAbs](https://nevware21.github.io/ts-utils/typedoc/functions/mathAbs.html)(); [mathAcos](https://nevware21.github.io/ts-utils/typedoc/functions/mathAcos.html)(); [mathAsin](https://nevware21.github.io/ts-utils/typedoc/functions/mathAsin.html)(); [mathAtan](https://nevware21.github.io/ts-utils/typedoc/functions/mathAtan.html)(); [mathAtan2](https://nevware21.github.io/ts-utils/typedoc/functions/mathAtan2.html)(); [mathCeil](https://nevware21.github.io/ts-utils/typedoc/functions/mathCeil.html)(); [mathCos](https://nevware21.github.io/ts-utils/typedoc/functions/mathCos.html)(); [mathExp](https://nevware21.github.io/ts-utils/typedoc/functions/mathExp.html)(); [mathFloor](https://nevware21.github.io/ts-utils/typedoc/functions/mathFloor.html)(); [mathLog](https://nevware21.github.io/ts-utils/typedoc/functions/mathLog.html)(); [mathMax](https://nevware21.github.io/ts-utils/typedoc/functions/mathMax.html)(); [mathMin](https://nevware21.github.io/ts-utils/typedoc/functions/mathMin.html)(); [mathPow](https://nevware21.github.io/ts-utils/typedoc/functions/mathPow.html)(); [mathRandom](https://nevware21.github.io/ts-utils/typedoc/functions/mathRandom.html)(); [mathRound](https://nevware21.github.io/ts-utils/typedoc/functions/mathRound.html)(); [mathSin](https://nevware21.github.io/ts-utils/typedoc/functions/mathSin.html)(); [mathSqrt](https://nevware21.github.io/ts-utils/typedoc/functions/mathSqrt.html)(); [mathTan](https://nevware21.github.io/ts-utils/typedoc/functions/mathTan.html)(); [mathToInt](https://nevware21.github.io/ts-utils/typedoc/functions/mathToInt.html)(); [mathTrunc](https://nevware21.github.io/ts-utils/typedoc/functions/mathTrunc.html)();
| Object | [deepExtend](https://nevware21.github.io/ts-utils/typedoc/functions/deepExtend.html)(); [forEachOwnKey](https://nevware21.github.io/ts-utils/typedoc/functions/forEachOwnKey.html)(); [forEachOwnKeySafe](https://nevware21.github.io/ts-utils/typedoc/functions/forEachOwnKeySafe.html)(); [isObject](https://nevware21.github.io/ts-utils/typedoc/functions/isObject.html)(); [isUnsafePropKey](https://nevware21.github.io/ts-utils/typedoc/functions/isUnsafePropKey.html)(); [isUnsafeTarget](https://nevware21.github.io/ts-utils/typedoc/functions/isUnsafeTarget.html)(); [objAssign](https://nevware21.github.io/ts-utils/typedoc/functions/objAssign.html)(); [objCopyProps](https://nevware21.github.io/ts-utils/typedoc/functions/objCopyProps.html)(); [objCreate](https://nevware21.github.io/ts-utils/typedoc/functions/objCreate.html)(); [objDeepCopy](https://nevware21.github.io/ts-utils/typedoc/functions/objDeepCopy.html)(); [objDeepFreeze](https://nevware21.github.io/ts-utils/typedoc/functions/objDeepFreeze.html)(); [objDefaults](https://nevware21.github.io/ts-utils/typedoc/functions/objDefaults.html)(); [objDefine](https://nevware21.github.io/ts-utils/typedoc/functions/objDefine.html)(); [objDefineAccessors](https://nevware21.github.io/ts-utils/typedoc/functions/objDefineAccessors.html)(); [objDefineGet](https://nevware21.github.io/ts-utils/typedoc/functions/objDefineGet.html)(); [objDefineProp](https://nevware21.github.io/ts-utils/typedoc/functions/objDefineProp.html)(); [objDefineProps](https://nevware21.github.io/ts-utils/typedoc/functions/objDefineProps.html)(); [objDefineProperties](https://nevware21.github.io/ts-utils/typedoc/functions/objDefineProperties.html)(); [objDiff](https://nevware21.github.io/ts-utils/typedoc/functions/objDiff.html)(); [objEntries](https://nevware21.github.io/ts-utils/typedoc/functions/objEntries.html)(); [objExtend](https://nevware21.github.io/ts-utils/typedoc/functions/objExtend.html)(); [objForEachKey](https://nevware21.github.io/ts-utils/typedoc/functions/objForEachKey.html)(); [objForEachKeySafe](https://nevware21.github.io/ts-utils/typedoc/functions/objForEachKeySafe.html)(); [objFreeze](https://nevware21.github.io/ts-utils/typedoc/functions/objFreeze.html)(); [objFromEntries](https://nevware21.github.io/ts-utils/typedoc/functions/objFromEntries.html)(); [objGetOwnPropertyDescriptor](https://nevware21.github.io/ts-utils/typedoc/functions/objGetOwnPropertyDescriptor.html)(); [objGetOwnPropertyDescriptors](https://nevware21.github.io/ts-utils/typedoc/functions/objGetOwnPropertyDescriptors.html)(); [objGetOwnPropertyNames](https://nevware21.github.io/ts-utils/typedoc/functions/objGetOwnPropertyNames.html)(); [objGetOwnPropertySymbols](https://nevware21.github.io/ts-utils/typedoc/functions/objGetOwnPropertySymbols.html)(); [objHasOwn](https://nevware21.github.io/ts-utils/typedoc/functions/objHasOwn.html)(); [objHasOwnProperty](https://nevware21.github.io/ts-utils/typedoc/functions/objHasOwnProperty.html)(); [objIs](https://nevware21.github.io/ts-utils/typedoc/functions/objIs.html)(); [objIsExtensible](https://nevware21.github.io/ts-utils/typedoc/functions/objIsExtensible.html)(); [objIsFrozen](https://nevware21.github.io/ts-utils/typedoc/functions/objIsFrozen.html)(); [objIsSealed](https://nevware21.github.io/ts-utils/typedoc/functions/objIsSealed.html)(); [objKeys](https://nevware21.github.io/ts-utils/typedoc/functions/objKeys.html)(); [objMapValues](https://nevware21.github.io/ts-utils/typedoc/functions/objMapValues.html)(); [objMergeIf](https://nevware21.github.io/ts-utils/typedoc/functions/objMergeIf.html)(); [objOmit](https://nevware21.github.io/ts-utils/typedoc/functions/objOmit.html)(); [objOmitBy](https://nevware21.github.io/ts-utils/typedoc/functions/objOmitBy.html)(); [objPick](https://nevware21.github.io/ts-utils/typedoc/functions/objPick.html)(); [objPickBy](https://nevware21.github.io/ts-utils/typedoc/functions/objPickBy.html)(); [objPreventExtensions](https://nevware21.github.io/ts-utils/typedoc/functions/objPreventExtensions.html)(); [objPropertyIsEnumerable](https://nevware21.github.io/ts-utils/typedoc/functions/objPropertyIsEnumerable.html)(); [objSeal](https://nevware21.github.io/ts-utils/typedoc/functions/objSeal.html)(); [objGetPrototypeOf](https://nevware21.github.io/ts-utils/typedoc/functions/objGetPrototypeOf.html)(); [objSetPrototypeOf](https://nevware21.github.io/ts-utils/typedoc/functions/objSetPrototypeOf.html)(); [objToString](https://nevware21.github.io/ts-utils/typedoc/functions/objToString.html)(); [objValues](https://nevware21.github.io/ts-utils/typedoc/functions/objValues.html)();
[polyObjEntries](https://nevware21.github.io/ts-utils/typedoc/functions/polyObjEntries.html)(); [polyObjIs](https://nevware21.github.io/ts-utils/typedoc/functions/polyObjIs.html)(); [polyObjKeys](https://nevware21.github.io/ts-utils/typedoc/functions/polyObjKeys.html)();
diff --git a/docs/feature-backlog.md b/docs/feature-backlog.md
index ec2bb516..64d65f57 100644
--- a/docs/feature-backlog.md
+++ b/docs/feature-backlog.md
@@ -33,18 +33,9 @@ Notes:
- These are direct language-native wrappers with ES version markers for polyfill candidates
- Other suggestions below are library-level utilities (not direct language features).
-- Iterator helpers are intentionally listed as utility suggestions here rather than standard-language mappings.
- Implementations should include ES5 polyfills where applicable for v0.x/v1.x compatibility
-### A. Iterator and Collection Helpers (Medium Value)
-
-- `iterMap`, `iterFilter`, `iterTake` – Iterator transformation helpers
-- `iterReduce`, `iterSome`, `iterEvery` – Iterator reduction/testing
-- `iterToArray` for predictable materialization of iterables / iterators
-- `arrToMap` helpers with stable key selection
-- lightweight set operations for iterables
-
-### B. Reliability and Tooling (High Value)
+### A. Reliability and Tooling (High Value)
- keep bundle-size thresholds justified with measured report
- require test parity for polyfill vs native behavior
diff --git a/lib/src/array/arrToMap.ts b/lib/src/array/arrToMap.ts
new file mode 100644
index 00000000..0282292a
--- /dev/null
+++ b/lib/src/array/arrToMap.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 { isUnsafePropKey } from "../object/isUnsafePropKey";
+import { iterForOf } from "../iterator/forOf";
+import { ArrToMapKeySelectorFn, ArrToMapValueSelectorFn } from "../iterator/types";
+import { arrForEach } from "./forEach";
+
+/**
+ * Creates an object map from array-like, iterator or iterable values.
+ *
+ * Keys are generated in stable source order via `keySelector`; later duplicate keys overwrite earlier values.
+ * Unsafe keys (`__proto__`, `constructor`, `prototype`) are ignored.
+ * @since 0.15.0
+ * @group Array
+ * @example
+ * ```ts
+ * const users = [
+ * { id: "u1", name: "Ada" },
+ * { id: "u2", name: "Lin" },
+ * { id: "u1", name: "Ada Updated" }
+ * ];
+ *
+ * arrToMap(users, (value) => value.id, (value) => value.name);
+ * // { u1: "Ada Updated", u2: "Lin" }
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function arrToMap(values: ArrayLike | Iterator | Iterable, keySelector: ArrToMapKeySelectorFn): { [key: string]: T };
+/*#__NO_SIDE_EFFECTS__*/
+export function arrToMap(values: ArrayLike | Iterator | Iterable, keySelector: ArrToMapKeySelectorFn, valueSelector: ArrToMapValueSelectorFn): { [key: string]: V };
+/*#__NO_SIDE_EFFECTS__*/
+export function arrToMap(values: ArrayLike | Iterator | Iterable, keySelector: ArrToMapKeySelectorFn, valueSelector?: ArrToMapValueSelectorFn): { [key: string]: V } {
+ let result: { [key: string]: V } = {};
+
+ function _processValue(value: T, index?: number) {
+ let valueIndex = index || 0;
+ let key = keySelector(value, valueIndex);
+ let keyValue = key + "";
+ if (!isUnsafePropKey(keyValue)) {
+ result[keyValue] = valueSelector ? valueSelector(value, valueIndex) : (value as any as V);
+ }
+ }
+
+ if (isArrayLike(values)) {
+ arrForEach(values, _processValue);
+ } else {
+ iterForOf(values as Iterator | Iterable, _processValue);
+ }
+
+
+ return result;
+}
diff --git a/lib/src/funcs/fnBindArgs.ts b/lib/src/funcs/fnBindArgs.ts
index 7832c687..023e2b26 100644
--- a/lib/src/funcs/fnBindArgs.ts
+++ b/lib/src/funcs/fnBindArgs.ts
@@ -37,8 +37,11 @@ import { BoundFunction } from "./types";
* bound("!"); // "Hi friend!"
* ```
*/
+/*#__NO_SIDE_EFFECTS__*/
export function fnBindArgs any, T, TArgs extends any[]>(fn: F, thisArg: T, argArray: TArgs): BoundFunction;
+/*#__NO_SIDE_EFFECTS__*/
export function fnBindArgs any, T>(fn: F, thisArg: T): F;
+/*#__NO_SIDE_EFFECTS__*/
export function fnBindArgs any, T>(fn: F, thisArg: T, argArray?: any[]): any {
return fn.bind.apply(fn, (argArray ? [ thisArg ].concat(argArray) : [ thisArg ]) as any);
}
diff --git a/lib/src/funcs/funcs.ts b/lib/src/funcs/funcs.ts
index 2ea4a666..62c7b903 100644
--- a/lib/src/funcs/funcs.ts
+++ b/lib/src/funcs/funcs.ts
@@ -214,6 +214,7 @@ export function fnCall any, T>(fn: F, thisArg: T): R
* module2.getX(); // 21
* ```
*/
+/*#__NO_SIDE_EFFECTS__*/
export function fnBind any, T>(fn: F, thisArg: T): F;
/**
@@ -250,6 +251,7 @@ export function fnBind any, T>(fn: F, thisArg: T):
* module2.getX(); // 21
* ```
*/
+/*#__NO_SIDE_EFFECTS__*/
export function fnBind any, T, TArgs extends any[]>(fn: F, thisArg: T, ...argArray: TArgs): BoundFunction;
/**
@@ -276,8 +278,10 @@ export function fnBind any, T, TArgs extends any[]
* bound("friend"); // "Hello friend"
* ```
*/
+/*#__NO_SIDE_EFFECTS__*/
export function fnBind(fn: F, thisArg: T, ...argArray: any[]): F;
+/*#__NO_SIDE_EFFECTS__*/
export function fnBind any, T>(fn: F, thisArg: T): any {
return fn.bind.apply(fn, ArrSlice[CALL](arguments, 1) as any);
}
diff --git a/lib/src/index.ts b/lib/src/index.ts
index 50aa0c7b..49d888b5 100644
--- a/lib/src/index.ts
+++ b/lib/src/index.ts
@@ -12,6 +12,7 @@ export { arrAppend } from "./array/append";
export { arrConcat } from "./array/concat";
export { ArrPredicateCallbackFn, ArrPredicateCallbackFn2, ArrMapCallbackFn, ArrFlatMapCallbackFn, ArrFromMapFn } from "./array/callbacks";
export { arrAt } from "./array/at";
+export { arrToMap } from "./array/arrToMap";
export { arrChunk } from "./array/chunk";
export { arrCompact } from "./array/compact";
export { arrDifference } from "./array/difference";
@@ -91,6 +92,17 @@ export { hasValue } from "./helpers/value";
export { createArrayIterator } from "./iterator/array";
export { CreateIteratorContext, createIterator, createIterable, createIterableIterator, makeIterable } from "./iterator/create";
export { iterForOf } from "./iterator/forOf";
+export { IterMapCallbackFn, IterPredicateCallbackFn, IterReduceCallbackFn, ArrToMapKeySelectorFn, ArrToMapValueSelectorFn } from "./iterator/types";
+export { iterMap } from "./iterator/iterMap";
+export { iterFilter } from "./iterator/iterFilter";
+export { iterTake } from "./iterator/iterTake";
+export { iterReduce } from "./iterator/iterReduce";
+export { iterSome } from "./iterator/iterSome";
+export { iterEvery } from "./iterator/iterEvery";
+export { iterToArray } from "./iterator/iterToArray";
+export { iterUnion } from "./iterator/iterUnion";
+export { iterIntersection } from "./iterator/iterIntersection";
+export { iterDifference } from "./iterator/iterDifference";
export { isAsyncIterable, isIterable, isIterator } from "./iterator/iterator";
export { createRangeIterator } from "./iterator/range";
export { mathAbs } from "./math/abs";
diff --git a/lib/src/iterator/forOf.ts b/lib/src/iterator/forOf.ts
index eeb34954..ba820c98 100644
--- a/lib/src/iterator/forOf.ts
+++ b/lib/src/iterator/forOf.ts
@@ -64,8 +64,8 @@ export function iterForOf(iter: Iterator | Iterable, callbackfn: (value
}
if (isIterator(iter)) {
- let err: { e: any } = UNDEF_VALUE;
- let iterResult: IteratorResult = UNDEF_VALUE;
+ let err: { e: any } | undefined = UNDEF_VALUE;
+ let iterResult: IteratorResult | null | undefined = UNDEF_VALUE;
try {
let count = 0;
while(!(iterResult = iter.next()).done) {
diff --git a/lib/src/iterator/helpers.ts b/lib/src/iterator/helpers.ts
new file mode 100644
index 00000000..b150c6db
--- /dev/null
+++ b/lib/src/iterator/helpers.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 { fnCall } from "../funcs/funcs";
+import { isArrayLike, isStrictNullOrUndefined } from "../helpers/base";
+import { arrSlice } from "../array/slice";
+import { getKnownSymbol } from "../symbol/symbol";
+import { WellKnownSymbols } from "../symbol/well_known";
+import { createArrayIterator } from "./array";
+import { createIterableIterator } from "./create";
+import { isIterable, isIterator } from "./iterator";
+
+export function _asIterator(iter: Iterator | Iterable | ArrayLike): Iterator {
+ if (isIterator(iter)) {
+ return iter;
+ }
+
+ if (isArrayLike(iter)) {
+ return createArrayIterator(arrSlice(iter));
+ }
+
+ if (isIterable(iter)) {
+ let iteratorFn = (iter as any)[getKnownSymbol(WellKnownSymbols.iterator)];
+ if (iteratorFn) {
+ return fnCall(iteratorFn, iter);
+ }
+ }
+
+ return createIterableIterator({
+ n: function() {
+ return true;
+ }
+ });
+}
+
+export function _getIteratorThisArg(source: Iterator, thisArg?: any): any {
+ return isStrictNullOrUndefined(thisArg) ? source : thisArg;
+}
+
+export function _doIteratorReturn(source: Iterator, value?: R): R | undefined {
+ source.return && source.return(value as any);
+ return value;
+}
diff --git a/lib/src/iterator/iterDifference.ts b/lib/src/iterator/iterDifference.ts
new file mode 100644
index 00000000..5ea327d4
--- /dev/null
+++ b/lib/src/iterator/iterDifference.ts
@@ -0,0 +1,44 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { arrForEach } from "../array/forEach";
+import { arrIncludes } from "../array/includes";
+import { iterForOf } from "./forOf";
+import { iterToArray } from "./iterToArray";
+
+/**
+ * Returns values from `iter` that are absent from all `excludeIters`.
+ * @since 0.15.0
+ * @group Iterator
+ * @example
+ * ```ts
+ * iterDifference([1, 2, 3, 4, 5], [2, 5], [9, 4]); // [1, 3]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function iterDifference(iter: Iterator | Iterable, ...excludeIters: Array | Iterable>): T[] {
+ let sourceValues = iterToArray(iter);
+ let excludedValues: T[] = [];
+
+ arrForEach(excludeIters, (excludeIter) => {
+ iterForOf(excludeIter, (value) => {
+ if (!arrIncludes(excludedValues, value)) {
+ excludedValues.push(value);
+ }
+ });
+ });
+
+ let result: T[] = [];
+ arrForEach(sourceValues, (value) => {
+ if (!arrIncludes(excludedValues, value)) {
+ result.push(value);
+ }
+ });
+
+ return result;
+}
diff --git a/lib/src/iterator/iterEvery.ts b/lib/src/iterator/iterEvery.ts
new file mode 100644
index 00000000..2e44aba3
--- /dev/null
+++ b/lib/src/iterator/iterEvery.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 { fnCall } from "../funcs/funcs";
+import { iterForOf } from "./forOf";
+import { _asIterator, _getIteratorThisArg } from "./helpers";
+import { IterPredicateCallbackFn } from "./types";
+
+/**
+ * Tests whether all values in the iterator / iterable match the predicate.
+ * @since 0.15.0
+ * @group Iterator
+ * @example
+ * ```ts
+ * iterEvery([2, 4, 6], (value) => value % 2 === 0); // true
+ * iterEvery([2, 3, 6], (value) => value % 2 === 0); // false
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function iterEvery(iter: Iterator | Iterable, callbackfn: IterPredicateCallbackFn, thisArg?: any): boolean {
+ let source = _asIterator(iter);
+ let allMatched = true;
+
+ iterForOf(source, (value, count) => {
+ if (!fnCall(callbackfn, _getIteratorThisArg(source, thisArg), value, count)) {
+ allMatched = false;
+ return -1;
+ }
+ });
+
+ return allMatched;
+}
diff --git a/lib/src/iterator/iterFilter.ts b/lib/src/iterator/iterFilter.ts
new file mode 100644
index 00000000..ce07ad7e
--- /dev/null
+++ b/lib/src/iterator/iterFilter.ts
@@ -0,0 +1,52 @@
+/*
+ * @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 { createIterableIterator } from "./create";
+import { _asIterator, _doIteratorReturn, _getIteratorThisArg } from "./helpers";
+import { IterPredicateCallbackFn } from "./types";
+
+/**
+ * Creates a lazily filtered iterable iterator.
+ * @since 0.15.0
+ * @group Iterator
+ * @example
+ * ```ts
+ * const filtered = iterFilter([1, 2, 3, 4, 5], (value) => value % 2 === 0);
+ * iterToArray(filtered); // [2, 4]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function iterFilter(iter: Iterator | Iterable, callbackfn: IterPredicateCallbackFn, thisArg?: any): IterableIterator {
+ let source = _asIterator(iter);
+ let index = 0;
+ let isDone = false;
+
+ return createIterableIterator({
+ n: function() {
+ let hasValue = false;
+ while (!isDone && !hasValue) {
+ let next = source.next();
+ isDone = !!next.done;
+ if (!isDone) {
+ hasValue = !!fnCall(callbackfn, _getIteratorThisArg(source, thisArg), next.value, index);
+ if (hasValue) {
+ this.v = next.value;
+ }
+
+ index++;
+ }
+ }
+
+ return !hasValue;
+ },
+ r: function(value?: T) {
+ return _doIteratorReturn(source, value);
+ }
+ });
+}
diff --git a/lib/src/iterator/iterIntersection.ts b/lib/src/iterator/iterIntersection.ts
new file mode 100644
index 00000000..166b66a3
--- /dev/null
+++ b/lib/src/iterator/iterIntersection.ts
@@ -0,0 +1,51 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { arrForEach } from "../array/forEach";
+import { arrIncludes } from "../array/includes";
+import { iterToArray } from "./iterToArray";
+
+/**
+ * Returns values that are present in every provided iterator / iterable.
+ * @since 0.15.0
+ * @group Iterator
+ * @example
+ * ```ts
+ * iterIntersection([1, 2, 3, 4], [2, 4, 6], [0, 2, 4]); // [2, 4]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function iterIntersection(...iters: Array | Iterable>): T[] {
+ if (iters.length === 0) {
+ return [];
+ }
+
+ let result: T[] = [];
+ let firstValues = iterToArray(iters[0]);
+ let otherValues: T[][] = [];
+
+ for (let lp = 1; lp < iters.length; lp++) {
+ otherValues.push(iterToArray(iters[lp]));
+ }
+
+ arrForEach(firstValues, (value) => {
+ let inAll = true;
+ arrForEach(otherValues, (other) => {
+ if (!arrIncludes(other, value)) {
+ inAll = false;
+ return -1;
+ }
+ });
+
+ if (inAll && !arrIncludes(result, value)) {
+ result.push(value);
+ }
+ });
+
+ return result;
+}
diff --git a/lib/src/iterator/iterMap.ts b/lib/src/iterator/iterMap.ts
new file mode 100644
index 00000000..ae9683b9
--- /dev/null
+++ b/lib/src/iterator/iterMap.ts
@@ -0,0 +1,47 @@
+/*
+ * @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 { createIterableIterator } from "./create";
+import { _asIterator, _doIteratorReturn, _getIteratorThisArg } from "./helpers";
+import { IterMapCallbackFn } from "./types";
+
+/**
+ * Creates a lazily mapped iterable iterator.
+ * @since 0.15.0
+ * @group Iterator
+ * @example
+ * ```ts
+ * const mapped = iterMap([1, 2, 3], (value) => value * 10);
+ * iterToArray(mapped); // [10, 20, 30]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function iterMap(iter: Iterator | Iterable, callbackfn: IterMapCallbackFn, thisArg?: any): IterableIterator {
+ let source = _asIterator(iter);
+ let index = 0;
+ let isDone = false;
+
+ return createIterableIterator({
+ n: function() {
+ if (!isDone) {
+ let next = source.next();
+ isDone = !!next.done;
+ if (!isDone) {
+ this.v = fnCall(callbackfn, _getIteratorThisArg(source, thisArg), next.value, index);
+ index++;
+ }
+ }
+
+ return isDone;
+ },
+ r: function(value?: R) {
+ return _doIteratorReturn(source, value);
+ }
+ });
+}
diff --git a/lib/src/iterator/iterReduce.ts b/lib/src/iterator/iterReduce.ts
new file mode 100644
index 00000000..5a7211a5
--- /dev/null
+++ b/lib/src/iterator/iterReduce.ts
@@ -0,0 +1,44 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { throwTypeError } from "../helpers/throw";
+import { iterForOf } from "./forOf";
+import { _asIterator } from "./helpers";
+import { IterReduceCallbackFn } from "./types";
+
+/**
+ * Reduces an iterator / iterable into a single value.
+ * @since 0.15.0
+ * @group Iterator
+ * @example
+ * ```ts
+ * iterReduce([1, 2, 3, 4], (prev, value) => (prev as number) + value, 0); // 10
+ * iterReduce([4, 9, 2], (prev, value) => (prev as number) > value ? (prev as number) : value); // 9
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function iterReduce(iter: Iterator | Iterable, callbackfn: IterReduceCallbackFn, initialValue?: T | R): R {
+ let source = _asIterator(iter);
+ let hasAccumulator = arguments.length > 2;
+ let accumulator = initialValue as T | R;
+
+ iterForOf(source, (value, count) => {
+ if (!hasAccumulator) {
+ accumulator = value;
+ hasAccumulator = true;
+ } else {
+ accumulator = callbackfn(accumulator, value, count, source);
+ }
+ });
+
+ if (!hasAccumulator) {
+ throwTypeError("Reduce of empty iterator with no initial value");
+ }
+
+ return accumulator as R;
+}
diff --git a/lib/src/iterator/iterSome.ts b/lib/src/iterator/iterSome.ts
new file mode 100644
index 00000000..613e4dc9
--- /dev/null
+++ b/lib/src/iterator/iterSome.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 { fnCall } from "../funcs/funcs";
+import { iterForOf } from "./forOf";
+import { _asIterator, _getIteratorThisArg } from "./helpers";
+import { IterPredicateCallbackFn } from "./types";
+
+/**
+ * Tests whether at least one value in the iterator / iterable matches the predicate.
+ * @since 0.15.0
+ * @group Iterator
+ * @example
+ * ```ts
+ * iterSome([1, 3, 5, 8], (value) => value % 2 === 0); // true
+ * iterSome([1, 3, 5], (value) => value % 2 === 0); // false
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function iterSome(iter: Iterator | Iterable, callbackfn: IterPredicateCallbackFn, thisArg?: any): boolean {
+ let source = _asIterator(iter);
+ let matched = false;
+
+ iterForOf(source, (value, count) => {
+ if (fnCall(callbackfn, _getIteratorThisArg(source, thisArg), value, count)) {
+ matched = true;
+ return -1;
+ }
+ });
+
+ return matched;
+}
diff --git a/lib/src/iterator/iterTake.ts b/lib/src/iterator/iterTake.ts
new file mode 100644
index 00000000..8f4b5f03
--- /dev/null
+++ b/lib/src/iterator/iterTake.ts
@@ -0,0 +1,67 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { createIterableIterator } from "./create";
+import { _asIterator, _doIteratorReturn } from "./helpers";
+import { mathFloor } from "../math/floor";
+
+/**
+ * Creates a lazy iterator that yields at most `count` values.
+ * @since 0.15.0
+ * @group Iterator
+ * @example
+ * ```ts
+ * const firstThree = iterTake([10, 20, 30, 40, 50], 3);
+ * iterToArray(firstThree); // [10, 20, 30]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function iterTake(iter: Iterator | Iterable, count: number): IterableIterator {
+ let source = _asIterator(iter);
+ let remaining = count > 0 ? mathFloor(count) : 0;
+ let complete = false;
+
+ function _complete(value?: T): T | undefined {
+ if (!complete) {
+ complete = true;
+ return _doIteratorReturn(source, value);
+ }
+
+ return value;
+ }
+
+ return createIterableIterator({
+ n: function() {
+ let isDone = true;
+
+ if (!complete) {
+ if (remaining <= 0) {
+ _complete();
+ } else {
+ let next = source.next();
+ if (next.done) {
+ complete = true;
+ } else {
+ this.v = next.value;
+ remaining--;
+ if (remaining <= 0) {
+ _complete();
+ }
+
+ isDone = false;
+ }
+ }
+ }
+
+ return isDone;
+ },
+ r: function(value?: T) {
+ return _complete(value);
+ }
+ });
+}
diff --git a/lib/src/iterator/iterToArray.ts b/lib/src/iterator/iterToArray.ts
new file mode 100644
index 00000000..c7eea9a5
--- /dev/null
+++ b/lib/src/iterator/iterToArray.ts
@@ -0,0 +1,41 @@
+/*
+ * @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 { isFunction } from "../helpers/base";
+import { iterForOf } from "./forOf";
+import { _asIterator, _getIteratorThisArg } from "./helpers";
+import { IterMapCallbackFn } from "./types";
+
+/**
+ * Materializes an iterator / iterable / array-like value as an array.
+ * @since 0.15.0
+ * @group Iterator
+ * @example
+ * ```ts
+ * iterToArray(createRangeIterator(1, 3)); // [1, 2, 3]
+ * iterToArray([10, 20, 30], (value, idx) => value + idx); // [10, 21, 32]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function iterToArray(iter: Iterator | Iterable | ArrayLike, mapFn?: IterMapCallbackFn, thisArg?: any): R[] {
+ let source = _asIterator(iter);
+ let values: R[] = [];
+
+ if (isFunction(mapFn)) {
+ iterForOf(source, (value, count) => {
+ values.push(fnCall(mapFn, _getIteratorThisArg(source, thisArg), value, count || 0));
+ });
+ } else {
+ iterForOf(source, (value) => {
+ values.push(value as any as R);
+ });
+ }
+
+ return values;
+}
diff --git a/lib/src/iterator/iterUnion.ts b/lib/src/iterator/iterUnion.ts
new file mode 100644
index 00000000..bdf45f87
--- /dev/null
+++ b/lib/src/iterator/iterUnion.ts
@@ -0,0 +1,34 @@
+/*
+ * @nevware21/ts-utils
+ * https://github.com/nevware21/ts-utils
+ *
+ * Copyright (c) 2026 NevWare21 Solutions LLC
+ * Licensed under the MIT license.
+ */
+
+import { arrIncludes } from "../array/includes";
+import { iterForOf } from "./forOf";
+
+/**
+ * Returns unique values from all provided iterators / iterables.
+ * @since 0.15.0
+ * @group Iterator
+ * @example
+ * ```ts
+ * iterUnion([1, 2, 3], [3, 4], createRangeIterator(4, 5)); // [1, 2, 3, 4, 5]
+ * ```
+ */
+/*#__NO_SIDE_EFFECTS__*/
+export function iterUnion(...iters: Array | Iterable>): T[] {
+ let result: T[] = [];
+
+ for (let lp = 0; lp < iters.length; lp++) {
+ iterForOf(iters[lp], (value) => {
+ if (!arrIncludes(result, value)) {
+ result.push(value);
+ }
+ });
+ }
+
+ return result;
+}
diff --git a/lib/src/iterator/types.ts b/lib/src/iterator/types.ts
new file mode 100644
index 00000000..4343c2fe
--- /dev/null
+++ b/lib/src/iterator/types.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.
+ */
+
+/**
+ * Callback signature for {@link iterMap}.
+ * @since 0.15.0
+ * @group Iterator
+ * @example
+ * ```ts
+ * const toLabel: IterMapCallbackFn = (value, index) => index + ":" + value;
+ * ```
+ */
+export type IterMapCallbackFn = (value: T, index: number) => R;
+
+/**
+ * Callback signature for {@link iterFilter}, {@link iterSome} and {@link iterEvery}.
+ * @since 0.15.0
+ * @group Iterator
+ * @example
+ * ```ts
+ * const isEven: IterPredicateCallbackFn = (value) => value % 2 === 0;
+ * ```
+ */
+export type IterPredicateCallbackFn = (value: T, index: number) => unknown;
+
+/**
+ * Callback signature for {@link iterReduce}.
+ * @since 0.15.0
+ * @group Iterator
+ * @example
+ * ```ts
+ * const sum: IterReduceCallbackFn = (previous, value) => (previous as number) + value;
+ * ```
+ */
+export type IterReduceCallbackFn = (previousValue: T | R, currentValue: T, currentIndex: number, iter: Iterator) => R;
+
+/**
+ * Callback signature for key selection in {@link arrToMap}.
+ * @since 0.15.0
+ * @group Array
+ * @example
+ * ```ts
+ * const byId: ArrToMapKeySelectorFn<{ id: string }> = (value) => value.id;
+ * ```
+ */
+export type ArrToMapKeySelectorFn = (value: T, index: number) => string | number;
+
+/**
+ * Callback signature for value selection in {@link arrToMap}.
+ * @since 0.15.0
+ * @group Array
+ * @example
+ * ```ts
+ * const pickName: ArrToMapValueSelectorFn<{ name: string }, string> = (value) => value.name;
+ * ```
+ */
+export type ArrToMapValueSelectorFn = (value: T, index: number) => V;
diff --git a/lib/test/bundle-size-check.js b/lib/test/bundle-size-check.js
index 2fd2fc86..9289185a 100644
--- a/lib/test/bundle-size-check.js
+++ b/lib/test/bundle-size-check.js
@@ -7,25 +7,25 @@ const configs = [
{
name: "es5-min-full",
path: "../bundle/es5/umd/ts-utils.min.js",
- limit: 38.5 * 1024, // 38.5 kb in bytes
+ limit: 40.5 * 1024, // 40.5 kb in bytes
compress: false
},
{
name: "es6-min-full",
path: "../bundle/es6/umd/ts-utils.min.js",
- limit: 37.5 * 1024, // 37.5 kb in bytes
+ limit: 39.5 * 1024, // 39.5 kb in bytes
compress: false
},
{
name: "es5-min-zip",
path: "../bundle/es5/umd/ts-utils.min.js",
- limit: 15 * 1024, // 15 kb in bytes
+ limit: 15.5 * 1024, // 15.5 kb in bytes
compress: true
},
{
name: "es6-min-zip",
path: "../bundle/es6/umd/ts-utils.min.js",
- limit: 15 * 1024, // 15 kb in bytes
+ limit: 15.5 * 1024, // 15.5 kb in bytes
compress: true
},
{
diff --git a/lib/test/src/common/array/arrToMap.test.ts b/lib/test/src/common/array/arrToMap.test.ts
new file mode 100644
index 00000000..0e72c22e
--- /dev/null
+++ b/lib/test/src/common/array/arrToMap.test.ts
@@ -0,0 +1,34 @@
+/*
+ * @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 { arrToMap } from "../../../../src/array/arrToMap";
+
+describe("arrToMap", () => {
+ it("creates stable key/value lookup", () => {
+ let entries = [
+ { id: "a", value: 10 },
+ { id: "b", value: 20 },
+ { id: "a", value: 99 }
+ ];
+
+ let mapped = arrToMap(entries, (value) => value.id, (value) => value.value);
+ assert.equal(mapped.a, 99, "later duplicate keys overwrite earlier values");
+ assert.equal(mapped.b, 20);
+
+ let unsafeMapped = arrToMap([
+ { key: "__proto__", value: 1 },
+ { key: "constructor", value: 2 },
+ { key: "ok", value: 3 }
+ ], (value) => value.key, (value) => value.value);
+
+ assert.equal((unsafeMapped as any).ok, 3);
+ assert.equal((unsafeMapped as any).__proto__, Object.prototype);
+ assert.equal((unsafeMapped as any).constructor, Object);
+ });
+});
diff --git a/lib/test/src/common/iterator/iterDifference.test.ts b/lib/test/src/common/iterator/iterDifference.test.ts
new file mode 100644
index 00000000..3bcacf02
--- /dev/null
+++ b/lib/test/src/common/iterator/iterDifference.test.ts
@@ -0,0 +1,23 @@
+/*
+ * @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 { createArrayIterator } from "../../../../src/iterator/array";
+import { iterDifference } from "../../../../src/iterator/iterDifference";
+
+describe("iterDifference", () => {
+ it("returns values absent from all exclude iterables", () => {
+ let difference = iterDifference([1, 2, 3, 4, 5], createArrayIterator([2, 5]), [9, 4]);
+ assert.deepEqual(difference, [1, 3]);
+ });
+
+ it("treats NaN as excluded when present", () => {
+ let difference = iterDifference([NaN], [NaN]);
+ assert.deepEqual(difference, []);
+ });
+});
diff --git a/lib/test/src/common/iterator/iterEvery.test.ts b/lib/test/src/common/iterator/iterEvery.test.ts
new file mode 100644
index 00000000..cd0e65c5
--- /dev/null
+++ b/lib/test/src/common/iterator/iterEvery.test.ts
@@ -0,0 +1,17 @@
+/*
+ * @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 { iterEvery } from "../../../../src/iterator/iterEvery";
+
+describe("iterEvery", () => {
+ it("short-circuits when predicate fails", () => {
+ assert.equal(iterEvery([2, 4, 6], (value) => value % 2 === 0), true);
+ assert.equal(iterEvery([2, 3, 6], (value) => value % 2 === 0), false);
+ });
+});
diff --git a/lib/test/src/common/iterator/iterFilter.test.ts b/lib/test/src/common/iterator/iterFilter.test.ts
new file mode 100644
index 00000000..58cb8366
--- /dev/null
+++ b/lib/test/src/common/iterator/iterFilter.test.ts
@@ -0,0 +1,42 @@
+/*
+ * @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 { iterFilter } from "../../../../src/iterator/iterFilter";
+import { iterToArray } from "../../../../src/iterator/iterToArray";
+
+describe("iterFilter", () => {
+ it("filters values lazily", () => {
+ let values = iterToArray(iterFilter([1, 2, 3, 4, 5], (value) => value % 2 === 0));
+ assert.deepEqual(values, [2, 4]);
+ });
+
+ it("does not call source.next after completion", () => {
+ let callCount = 0;
+ let source: Iterator = {
+ next: () => {
+ callCount++;
+ if (callCount === 1) {
+ return { done: false, value: 1 };
+ }
+
+ if (callCount === 2) {
+ return { done: true, value: undefined as any };
+ }
+
+ throw new Error("next called after completion");
+ }
+ };
+
+ let filtered = iterFilter(source, () => true);
+ assert.deepEqual(filtered.next(), { done: false, value: 1 });
+ assert.equal(filtered.next().done, true);
+ assert.equal(filtered.next().done, true);
+ assert.equal(callCount, 2);
+ });
+});
diff --git a/lib/test/src/common/iterator/iterIntersection.test.ts b/lib/test/src/common/iterator/iterIntersection.test.ts
new file mode 100644
index 00000000..31bbe1c1
--- /dev/null
+++ b/lib/test/src/common/iterator/iterIntersection.test.ts
@@ -0,0 +1,30 @@
+/*
+ * @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 { createArrayIterator } from "../../../../src/iterator/array";
+import { iterIntersection } from "../../../../src/iterator/iterIntersection";
+
+describe("iterIntersection", () => {
+ it("returns values present in all iterables", () => {
+ let intersection = iterIntersection([1, 2, 3, 4], createArrayIterator([2, 4, 6]), [0, 2, 4]);
+ assert.deepEqual(intersection, [2, 4]);
+ });
+
+ it("treats NaN as present across inputs", () => {
+ let intersection = iterIntersection([NaN], [NaN]);
+ assert.equal(intersection.length, 1);
+ assert.equal(intersection[0] !== intersection[0], true);
+ });
+
+ it("deduplicates repeated NaN values from the first iterable", () => {
+ let intersection = iterIntersection([NaN, NaN, NaN], [NaN]);
+ assert.equal(intersection.length, 1);
+ assert.equal(intersection[0] !== intersection[0], true);
+ });
+});
diff --git a/lib/test/src/common/iterator/iterMap.test.ts b/lib/test/src/common/iterator/iterMap.test.ts
new file mode 100644
index 00000000..96740af1
--- /dev/null
+++ b/lib/test/src/common/iterator/iterMap.test.ts
@@ -0,0 +1,42 @@
+/*
+ * @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 { iterMap } from "../../../../src/iterator/iterMap";
+import { iterToArray } from "../../../../src/iterator/iterToArray";
+
+describe("iterMap", () => {
+ it("maps values lazily", () => {
+ let values = iterToArray(iterMap([1, 2, 3], (value) => value * 10));
+ assert.deepEqual(values, [10, 20, 30]);
+ });
+
+ it("does not call source.next after completion", () => {
+ let callCount = 0;
+ let source: Iterator = {
+ next: () => {
+ callCount++;
+ if (callCount === 1) {
+ return { done: false, value: 1 };
+ }
+
+ if (callCount === 2) {
+ return { done: true, value: undefined as any };
+ }
+
+ throw new Error("next called after completion");
+ }
+ };
+
+ let mapped = iterMap(source, (value) => value * 2);
+ assert.deepEqual(mapped.next(), { done: false, value: 2 });
+ assert.equal(mapped.next().done, true);
+ assert.equal(mapped.next().done, true);
+ assert.equal(callCount, 2);
+ });
+});
diff --git a/lib/test/src/common/iterator/iterReduce.test.ts b/lib/test/src/common/iterator/iterReduce.test.ts
new file mode 100644
index 00000000..7a3d2320
--- /dev/null
+++ b/lib/test/src/common/iterator/iterReduce.test.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.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { createArrayIterator } from "../../../../src/iterator/array";
+import { iterReduce } from "../../../../src/iterator/iterReduce";
+
+describe("iterReduce", () => {
+ it("supports with and without initial value", () => {
+ let total = iterReduce([1, 2, 3, 4], (previous, current) => (previous as number) + current, 0);
+ assert.equal(total, 10);
+
+ let maxValue = iterReduce(createArrayIterator([4, 9, 2]), (previous, current) => {
+ return (previous as number) > current ? (previous as number) : current;
+ });
+ assert.equal(maxValue, 9);
+
+ assert.throws(() => iterReduce([], (previous, current) => (previous as number) + current), TypeError);
+ });
+});
diff --git a/lib/test/src/common/iterator/iterSome.test.ts b/lib/test/src/common/iterator/iterSome.test.ts
new file mode 100644
index 00000000..8b6f1872
--- /dev/null
+++ b/lib/test/src/common/iterator/iterSome.test.ts
@@ -0,0 +1,17 @@
+/*
+ * @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 { iterSome } from "../../../../src/iterator/iterSome";
+
+describe("iterSome", () => {
+ it("short-circuits when predicate matches", () => {
+ assert.equal(iterSome([1, 3, 5, 8], (value) => value % 2 === 0), true);
+ assert.equal(iterSome([1, 3, 5], (value) => value % 2 === 0), false);
+ });
+});
diff --git a/lib/test/src/common/iterator/iterTake.test.ts b/lib/test/src/common/iterator/iterTake.test.ts
new file mode 100644
index 00000000..f6ad8a6d
--- /dev/null
+++ b/lib/test/src/common/iterator/iterTake.test.ts
@@ -0,0 +1,49 @@
+/*
+ * @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 { iterTake } from "../../../../src/iterator/iterTake";
+import { iterToArray } from "../../../../src/iterator/iterToArray";
+
+describe("iterTake", () => {
+ it("returns at most the requested number of values", () => {
+ let values = iterToArray(iterTake([10, 20, 30, 40, 50], 3));
+ assert.deepEqual(values, [10, 20, 30]);
+ });
+
+ it("normalizes fractional counts to an integer limit", () => {
+ assert.deepEqual(iterToArray(iterTake([1, 2], 0.5)), []);
+ assert.deepEqual(iterToArray(iterTake([1, 2, 3, 4], 2.5)), [1, 2]);
+ });
+
+ it("closes the wrapped iterator when the count limit is reached", () => {
+ let nextCount = 0;
+ let returnCount = 0;
+ let source: Iterator = {
+ next: () => {
+ nextCount++;
+ return {
+ done: false,
+ value: nextCount
+ };
+ },
+ return: (value?: any) => {
+ returnCount++;
+ return {
+ done: true,
+ value: value as number
+ };
+ }
+ };
+
+ let values = iterToArray(iterTake(source, 2));
+ assert.deepEqual(values, [1, 2]);
+ assert.equal(nextCount, 2, "source.next() should only be called for yielded values");
+ assert.equal(returnCount, 1, "source.return() should be called once when limit is reached");
+ });
+});
diff --git a/lib/test/src/common/iterator/iterToArray.test.ts b/lib/test/src/common/iterator/iterToArray.test.ts
new file mode 100644
index 00000000..8cb26d09
--- /dev/null
+++ b/lib/test/src/common/iterator/iterToArray.test.ts
@@ -0,0 +1,34 @@
+/*
+ * @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 { createArrayIterator } from "../../../../src/iterator/array";
+import { createRangeIterator } from "../../../../src/iterator/range";
+import { iterToArray } from "../../../../src/iterator/iterToArray";
+
+describe("iterToArray", () => {
+ it("supports iterables and iterators", () => {
+ let fromIterable = iterToArray(createRangeIterator(1, 3));
+ assert.deepEqual(fromIterable, [1, 2, 3]);
+
+ let fromIterator = iterToArray(createArrayIterator([10, 20, 30]), (value, idx) => value + idx);
+ assert.deepEqual(fromIterator, [10, 21, 32]);
+ });
+
+ it("supports array-like values", () => {
+ let arrayLike: ArrayLike = {
+ 0: 10,
+ 1: 20,
+ 2: 30,
+ length: 3
+ };
+
+ let values = iterToArray(arrayLike, (value, idx) => value + idx);
+ assert.deepEqual(values, [10, 21, 32]);
+ });
+});
diff --git a/lib/test/src/common/iterator/iterUnion.test.ts b/lib/test/src/common/iterator/iterUnion.test.ts
new file mode 100644
index 00000000..77e2d54b
--- /dev/null
+++ b/lib/test/src/common/iterator/iterUnion.test.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.
+ */
+
+import { assert } from "@nevware21/tripwire-chai";
+import { createArrayIterator } from "../../../../src/iterator/array";
+import { createRangeIterator } from "../../../../src/iterator/range";
+import { iterUnion } from "../../../../src/iterator/iterUnion";
+
+describe("iterUnion", () => {
+ it("returns unique values from all iterables", () => {
+ let union = iterUnion([1, 2, 3], createArrayIterator([3, 4, 5]), createRangeIterator(5, 6));
+ assert.deepEqual(union, [1, 2, 3, 4, 5, 6]);
+ });
+
+ it("treats NaN as a duplicate value", () => {
+ let union = iterUnion([NaN], [NaN]);
+ assert.equal(union.length, 1);
+ assert.equal(union[0] !== union[0], true);
+ });
+});