Skip to content

Commit 382853e

Browse files
authored
feat(iterator): add iterator collection helpers with docs and tests (#574)
- add new iterator helper module with typed exports: - iterMap, iterFilter, iterTake, iterReduce, iterSome, iterEvery, iterToArray - arrToMap, iterUnion, iterIntersection, iterDifference - IterMapCallbackFn, IterPredicateCallbackFn, IterReduceCallbackFn, ArrToMapKeySelectorFn, ArrToMapValueSelectorFn - export new iterator helpers from index.ts - add comprehensive common tests for helper behavior and edge cases in helpers.test.ts - add TypeDoc examples and mark new APIs as @SInCE 0.15.0 in helpers.ts - update Iterator utility matrix in README.md to include all new helper links
1 parent 87cb303 commit 382853e

33 files changed

Lines changed: 999 additions & 23 deletions

.size-limit.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,42 @@
22
{
33
"name": "es5-full",
44
"path": "lib/dist/es5/mod/ts-utils.js",
5-
"limit": "35 kb",
5+
"limit": "37 kb",
66
"brotli": false,
77
"running": false
88
},
99
{
1010
"name": "es6-full",
1111
"path": "lib/dist/es6/mod/ts-utils.js",
12-
"limit": "33.5 kb",
12+
"limit": "35.5 kb",
1313
"brotli": false,
1414
"running": false
1515
},
1616
{
1717
"name": "es5-full-brotli",
1818
"path": "lib/dist/es5/mod/ts-utils.js",
19-
"limit": "12.5 kb",
19+
"limit": "12.75 kb",
2020
"brotli": true,
2121
"running": false
2222
},
2323
{
2424
"name": "es6-full-brotli",
2525
"path": "lib/dist/es6/mod/ts-utils.js",
26-
"limit": "12 kb",
26+
"limit": "12.5 kb",
2727
"brotli": true,
2828
"running": false
2929
},
3030
{
3131
"name": "es5-zip",
3232
"path": "lib/dist/es5/mod/ts-utils.js",
33-
"limit": "13.5 Kb",
33+
"limit": "14 Kb",
3434
"gzip": true,
3535
"running": false
3636
},
3737
{
3838
"name": "es6-zip",
3939
"path": "lib/dist/es6/mod/ts-utils.js",
40-
"limit": "13.5 Kb",
40+
"limit": "14 Kb",
4141
"gzip": true,
4242
"running": false
4343
},

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
- Adds shared queue logic and callback-argument support across microtask and nextTick scheduling
1616
- Adds `arrConcat` as a dedicated array helper and `fnBindArgs` as a dedicated function helper
1717
- Improves function binding typing with exported `BoundFunction` and updated signatures for `fnBind` / `fnBindArgs`
18+
- [#574](https://github.com/nevware21/ts-utils/pull/574) feat(iterator,array): add iterator collection helpers, split helper modules, and align collection membership semantics
19+
- Added new iterator helpers: `iterMap`, `iterFilter`, `iterTake`, `iterReduce`, `iterSome`, `iterEvery`, `iterToArray`, `iterUnion`, `iterIntersection`, `iterDifference`
20+
- Added `arrToMap` helper in the array module and moved callback/type declarations into `iterator/types`
21+
- Refactored iterator helper implementation/tests into per-function files and updated root exports
22+
- Added NaN regression coverage and switched iterator set-operation membership checks to `arrIncludes` semantics for parity with array helpers
1823

1924
### Bug Fixes
2025

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ Below is a categorized list of all available utilities with direct links to thei
127127
| Error | <code>[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)();</code>
128128
| Function | <code>[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)();</code>
129129
| Idle | <code>[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)(); </code>
130-
| Iterator | <code>[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)();</code>
130+
| Iterator | <code>[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)();</code>
131131
| Number | <code>[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)();</code>
132132
| Math | <code>[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)();</code>
133133
| Object | <code>[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)();<br/>[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)();</code>

docs/feature-backlog.md

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,9 @@ Notes:
3333

3434
- These are direct language-native wrappers with ES version markers for polyfill candidates
3535
- Other suggestions below are library-level utilities (not direct language features).
36-
- Iterator helpers are intentionally listed as utility suggestions here rather than standard-language mappings.
3736
- Implementations should include ES5 polyfills where applicable for v0.x/v1.x compatibility
3837

39-
### A. Iterator and Collection Helpers (Medium Value)
40-
41-
- `iterMap`, `iterFilter`, `iterTake` – Iterator transformation helpers
42-
- `iterReduce`, `iterSome`, `iterEvery` – Iterator reduction/testing
43-
- `iterToArray` for predictable materialization of iterables / iterators
44-
- `arrToMap` helpers with stable key selection
45-
- lightweight set operations for iterables
46-
47-
### B. Reliability and Tooling (High Value)
38+
### A. Reliability and Tooling (High Value)
4839

4940
- keep bundle-size thresholds justified with measured report
5041
- require test parity for polyfill vs native behavior

lib/src/array/arrToMap.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* @nevware21/ts-utils
3+
* https://github.com/nevware21/ts-utils
4+
*
5+
* Copyright (c) 2026 NevWare21 Solutions LLC
6+
* Licensed under the MIT license.
7+
*/
8+
9+
import { isArrayLike } from "../helpers/base";
10+
import { isUnsafePropKey } from "../object/isUnsafePropKey";
11+
import { iterForOf } from "../iterator/forOf";
12+
import { ArrToMapKeySelectorFn, ArrToMapValueSelectorFn } from "../iterator/types";
13+
import { arrForEach } from "./forEach";
14+
15+
/**
16+
* Creates an object map from array-like, iterator or iterable values.
17+
*
18+
* Keys are generated in stable source order via `keySelector`; later duplicate keys overwrite earlier values.
19+
* Unsafe keys (`__proto__`, `constructor`, `prototype`) are ignored.
20+
* @since 0.15.0
21+
* @group Array
22+
* @example
23+
* ```ts
24+
* const users = [
25+
* { id: "u1", name: "Ada" },
26+
* { id: "u2", name: "Lin" },
27+
* { id: "u1", name: "Ada Updated" }
28+
* ];
29+
*
30+
* arrToMap(users, (value) => value.id, (value) => value.name);
31+
* // { u1: "Ada Updated", u2: "Lin" }
32+
* ```
33+
*/
34+
/*#__NO_SIDE_EFFECTS__*/
35+
export function arrToMap<T>(values: ArrayLike<T> | Iterator<T> | Iterable<T>, keySelector: ArrToMapKeySelectorFn<T>): { [key: string]: T };
36+
/*#__NO_SIDE_EFFECTS__*/
37+
export function arrToMap<T, V>(values: ArrayLike<T> | Iterator<T> | Iterable<T>, keySelector: ArrToMapKeySelectorFn<T>, valueSelector: ArrToMapValueSelectorFn<T, V>): { [key: string]: V };
38+
/*#__NO_SIDE_EFFECTS__*/
39+
export function arrToMap<T, V = T>(values: ArrayLike<T> | Iterator<T> | Iterable<T>, keySelector: ArrToMapKeySelectorFn<T>, valueSelector?: ArrToMapValueSelectorFn<T, V>): { [key: string]: V } {
40+
let result: { [key: string]: V } = {};
41+
42+
function _processValue(value: T, index?: number) {
43+
let valueIndex = index || 0;
44+
let key = keySelector(value, valueIndex);
45+
let keyValue = key + "";
46+
if (!isUnsafePropKey(keyValue)) {
47+
result[keyValue] = valueSelector ? valueSelector(value, valueIndex) : (value as any as V);
48+
}
49+
}
50+
51+
if (isArrayLike(values)) {
52+
arrForEach(values, _processValue);
53+
} else {
54+
iterForOf(values as Iterator<T> | Iterable<T>, _processValue);
55+
}
56+
57+
58+
return result;
59+
}

lib/src/funcs/fnBindArgs.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,11 @@ import { BoundFunction } from "./types";
3737
* bound("!"); // "Hi friend!"
3838
* ```
3939
*/
40+
/*#__NO_SIDE_EFFECTS__*/
4041
export function fnBindArgs<F extends (...args: any[]) => any, T, TArgs extends any[]>(fn: F, thisArg: T, argArray: TArgs): BoundFunction<F, TArgs>;
42+
/*#__NO_SIDE_EFFECTS__*/
4143
export function fnBindArgs<F extends (...args: any[]) => any, T>(fn: F, thisArg: T): F;
44+
/*#__NO_SIDE_EFFECTS__*/
4245
export function fnBindArgs<F extends (...args: any[]) => any, T>(fn: F, thisArg: T, argArray?: any[]): any {
4346
return fn.bind.apply(fn, (argArray ? [ thisArg ].concat(argArray) : [ thisArg ]) as any);
4447
}

lib/src/funcs/funcs.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ export function fnCall<F extends (...args: any) => any, T>(fn: F, thisArg: T): R
214214
* module2.getX(); // 21
215215
* ```
216216
*/
217+
/*#__NO_SIDE_EFFECTS__*/
217218
export function fnBind<F extends (...args: any[]) => any, T>(fn: F, thisArg: T): F;
218219

219220
/**
@@ -250,6 +251,7 @@ export function fnBind<F extends (...args: any[]) => any, T>(fn: F, thisArg: T):
250251
* module2.getX(); // 21
251252
* ```
252253
*/
254+
/*#__NO_SIDE_EFFECTS__*/
253255
export function fnBind<F extends (...args: any[]) => any, T, TArgs extends any[]>(fn: F, thisArg: T, ...argArray: TArgs): BoundFunction<F, TArgs>;
254256

255257
/**
@@ -276,8 +278,10 @@ export function fnBind<F extends (...args: any[]) => any, T, TArgs extends any[]
276278
* bound("friend"); // "Hello friend"
277279
* ```
278280
*/
281+
/*#__NO_SIDE_EFFECTS__*/
279282
export function fnBind<F extends Function, T>(fn: F, thisArg: T, ...argArray: any[]): F;
280283

284+
/*#__NO_SIDE_EFFECTS__*/
281285
export function fnBind<F extends (...args: any[]) => any, T>(fn: F, thisArg: T): any {
282286
return fn.bind.apply(fn, ArrSlice[CALL](arguments, 1) as any);
283287
}

0 commit comments

Comments
 (0)