throw a TypeError instead of RangeError on non integer number chunkSize / windowSize

https://github.com/tc39/proposal-iterator-chunking/pull/30
This commit is contained in:
Denis Pushkarev
2026-06-28 15:12:53 +07:00
parent 5d709706a5
commit ea3487a8a6
10 changed files with 48 additions and 17 deletions
+1
View File
@@ -10,6 +10,7 @@
- Built-ins:
- `Iterator.prototype.chunks`
- `Iterator.prototype.windows`
- Throw a `TypeError` instead of `RangeError` on non integer number `chunkSize` / `windowSize`, following [tc39/proposal-iterator-chunking/#30](https://github.com/tc39/proposal-iterator-chunking/pull/30)
- Moved to stage 3, [May 2026 TC39 meeting](https://github.com/tc39/proposals/commit/7226f0af93443025010efcad219115cec7dc8b2a)
- Added `/actual/` namespaces entries, unconditional forced replacement changed to feature detection
- [`Iterator` includes stage 3 proposal](https://github.com/tc39/proposal-iterator-includes):
@@ -0,0 +1,17 @@
'use strict';
var iteratorClose = require('../internals/iterator-close');
var $RangeError = RangeError;
var $TypeError = TypeError;
var floor = Math.floor;
var CHUNK_SIZE_VALIDATION_ERROR = 'Chunk size must be an integer in [1, 2^32-1]';
module.exports = function (chunkSize, iterator) {
if (typeof chunkSize != 'number' || floor(chunkSize) !== chunkSize) {
return iteratorClose(iterator, 'throw', new $TypeError(CHUNK_SIZE_VALIDATION_ERROR));
}
if (chunkSize === 0 || chunkSize >>> 0 !== chunkSize) {
return iteratorClose(iterator, 'throw', new $RangeError(CHUNK_SIZE_VALIDATION_ERROR));
}
};
@@ -5,9 +5,9 @@ var createIteratorProxy = require('../internals/iterator-create-proxy');
var createIterResultObject = require('../internals/create-iter-result-object');
var getIteratorDirect = require('../internals/get-iterator-direct');
var iteratorClose = require('../internals/iterator-close');
var chunkSizeValidation = require('../internals/iterator-chunk-size-validation');
var uncurryThis = require('../internals/function-uncurry-this');
var $RangeError = RangeError;
var $TypeError = TypeError;
var push = uncurryThis([].push);
var slice = uncurryThis([].slice);
@@ -36,9 +36,7 @@ var IteratorProxy = createIteratorProxy(function () {
// https://github.com/tc39/proposal-iterator-chunking
module.exports = function (O, windowSize, undersized) {
anObject(O);
if (typeof windowSize != 'number' || !windowSize || windowSize >>> 0 !== windowSize) {
return iteratorClose(O, 'throw', new $RangeError('`windowSize` must be integer in [1, 2^32-1]'));
}
chunkSizeValidation(windowSize, O);
if (undersized !== undefined && undersized !== 'only-full' && undersized !== ALLOW_PARTIAL) {
return iteratorClose(O, 'throw', new $TypeError('Incorrect `undersized` argument'));
}
@@ -4,11 +4,10 @@ var anObject = require('../internals/an-object');
var call = require('../internals/function-call');
var createIteratorProxy = require('../internals/iterator-create-proxy');
var getIteratorDirect = require('../internals/get-iterator-direct');
var iteratorClose = require('../internals/iterator-close');
var chunkSizeValidation = require('../internals/iterator-chunk-size-validation');
var uncurryThis = require('../internals/function-uncurry-this');
var IS_PURE = require('../internals/is-pure');
var $RangeError = RangeError;
var push = uncurryThis([].push);
var IteratorProxy = createIteratorProxy(function () {
@@ -34,11 +33,9 @@ var IteratorProxy = createIteratorProxy(function () {
// https://github.com/tc39/proposal-iterator-chunking
$({ target: 'Iterator', proto: true, real: true, forced: IS_PURE }, {
chunks: function chunks(chunkSize) {
var O = anObject(this);
if (typeof chunkSize != 'number' || !chunkSize || chunkSize >>> 0 !== chunkSize) {
return iteratorClose(O, 'throw', new $RangeError('`chunkSize` must be integer in [1, 2^32-1]'));
}
return new IteratorProxy(getIteratorDirect(O), {
anObject(this);
chunkSizeValidation(chunkSize, this);
return new IteratorProxy(getIteratorDirect(this), {
chunkSize: chunkSize
});
}
+4 -1
View File
@@ -32,8 +32,11 @@ QUnit.test('Iterator#chunks', assert => {
assert.throws(() => chunks.call(5, 1), TypeError, 'non-iterable-object this #3');
}
assert.throws(() => chunks.call(it), RangeError, 'throws on empty argument');
assert.throws(() => chunks.call(it), TypeError, 'throws on empty argument');
assert.throws(() => chunks.call(it, '2'), TypeError, 'throws on empty argument');
assert.throws(() => chunks.call(it, 2.1), TypeError, 'throws on empty argument');
assert.throws(() => chunks.call(it, -1), RangeError, 'throws on negative argument');
assert.throws(() => chunks.call(it, 2 ** 32), RangeError, 'throws on negative argument');
const observableReturn = {
return() {
+4 -1
View File
@@ -33,8 +33,11 @@ QUnit.test('Iterator#sliding', assert => {
assert.throws(() => sliding.call(5, 1), TypeError, 'non-iterable-object this #3');
}
assert.throws(() => sliding.call(it), RangeError, 'throws on empty argument');
assert.throws(() => sliding.call(it), TypeError, 'throws on empty argument');
assert.throws(() => sliding.call(it, '2'), TypeError, 'throws on empty argument');
assert.throws(() => sliding.call(it, 2.1), TypeError, 'throws on empty argument');
assert.throws(() => sliding.call(it, -1), RangeError, 'throws on negative argument');
assert.throws(() => sliding.call(it, 2 ** 32), RangeError, 'throws on negative argument');
const observableReturn = {
return() {
+4 -1
View File
@@ -36,8 +36,11 @@ QUnit.test('Iterator#windows', assert => {
assert.throws(() => windows.call(5, 1), TypeError, 'non-iterable-object this #3');
}
assert.throws(() => windows.call(it), RangeError, 'throws on empty argument');
assert.throws(() => windows.call(it), TypeError, 'throws on empty argument');
assert.throws(() => windows.call(it, '2'), TypeError, 'throws on empty argument');
assert.throws(() => windows.call(it, 2.1), TypeError, 'throws on empty argument');
assert.throws(() => windows.call(it, -1), RangeError, 'throws on negative argument');
assert.throws(() => windows.call(it, 2 ** 32), RangeError, 'throws on negative argument');
const observableReturn = {
return() {
+4 -1
View File
@@ -31,8 +31,11 @@ QUnit.test('Iterator#chunks', assert => {
assert.throws(() => chunks.call(5, 1), TypeError, 'non-iterable-object this #3');
}
assert.throws(() => chunks.call(it), RangeError, 'throws on empty argument');
assert.throws(() => chunks.call(it), TypeError, 'throws on empty argument');
assert.throws(() => chunks.call(it, '2'), TypeError, 'throws on empty argument');
assert.throws(() => chunks.call(it, 2.1), TypeError, 'throws on empty argument');
assert.throws(() => chunks.call(it, -1), RangeError, 'throws on negative argument');
assert.throws(() => chunks.call(it, 2 ** 32), RangeError, 'throws on negative argument');
const observableReturn = {
return() {
+4 -1
View File
@@ -32,8 +32,11 @@ QUnit.test('Iterator#sliding', assert => {
assert.throws(() => sliding.call(5, 1), TypeError, 'non-iterable-object this #3');
}
assert.throws(() => sliding.call(it), RangeError, 'throws on empty argument');
assert.throws(() => sliding.call(it), TypeError, 'throws on empty argument');
assert.throws(() => sliding.call(it, '2'), TypeError, 'throws on empty argument');
assert.throws(() => sliding.call(it, 2.1), TypeError, 'throws on empty argument');
assert.throws(() => sliding.call(it, -1), RangeError, 'throws on negative argument');
assert.throws(() => sliding.call(it, 2 ** 32), RangeError, 'throws on negative argument');
const observableReturn = {
return() {
+4 -1
View File
@@ -35,8 +35,11 @@ QUnit.test('Iterator#windows', assert => {
assert.throws(() => windows.call(5, 1), TypeError, 'non-iterable-object this #3');
}
assert.throws(() => windows.call(it), RangeError, 'throws on empty argument');
assert.throws(() => windows.call(it), TypeError, 'throws on empty argument');
assert.throws(() => windows.call(it, '2'), TypeError, 'throws on empty argument');
assert.throws(() => windows.call(it, 2.1), TypeError, 'throws on empty argument');
assert.throws(() => windows.call(it, -1), RangeError, 'throws on negative argument');
assert.throws(() => windows.call(it, 2 ** 32), RangeError, 'throws on negative argument');
const observableReturn = {
return() {