{"id":13482225,"url":"https://github.com/tc39/proposal-iterator-helpers","last_synced_at":"2025-03-27T12:32:36.303Z","repository":{"id":34015271,"uuid":"165733866","full_name":"tc39/proposal-iterator-helpers","owner":"tc39","description":"Methods for working with iterators in ECMAScript","archived":true,"fork":false,"pushed_at":"2024-10-08T04:41:47.000Z","size":521,"stargazers_count":1327,"open_issues_count":4,"forks_count":34,"subscribers_count":74,"default_branch":"main","last_synced_at":"2024-10-30T15:51:18.893Z","etag":null,"topics":["ecmascript-proposal","iterators","javascript","tc39"],"latest_commit_sha":null,"homepage":"https://tc39.es/proposal-iterator-helpers","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tc39.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-14T20:57:27.000Z","updated_at":"2024-10-30T15:36:58.000Z","dependencies_parsed_at":"2024-01-13T18:15:37.462Z","dependency_job_id":"71fd9fd6-fd3b-4d18-94b2-325781709346","html_url":"https://github.com/tc39/proposal-iterator-helpers","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-iterator-helpers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-iterator-helpers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-iterator-helpers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-iterator-helpers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tc39","download_url":"https://codeload.github.com/tc39/proposal-iterator-helpers/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245845382,"owners_count":20681903,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ecmascript-proposal","iterators","javascript","tc39"],"created_at":"2024-07-31T17:01:00.065Z","updated_at":"2025-03-27T12:32:35.988Z","avatar_url":"https://github.com/tc39.png","language":"HTML","readme":"# Iterator Helpers\n\n\u003e [!IMPORTANT]  \n\u003e This proposal is now a Stage 4 and will be merged into ECMA-262 as part of https://github.com/tc39/ecma262/pull/3395. This repo is no longer active.\n\nA proposal for several interfaces that will help with general usage and\nconsumption of iterators in ECMAScript.\n\n## Status\n\nAuthors: Gus Caplan, Michael Ficarra, Adam Vandolder, Jason Orendorff, Kevin Gibbons\n\nChampions: Michael Ficarra, Yulia Startsev\n\nThis proposal is at Stage 4 of [The TC39 Process](https://tc39.es/process-document/).\n\nThis proposal formerly contained async as well as sync helpers. The async helpers have been split out to [a separate proposal](https://github.com/tc39/proposal-async-iterator-helpers).\n\n## Motivation\n\nIterators are a useful way to represent large or possibly infinite enumerable data sets. However,\nthey lack helpers which make them as easy to use as Arrays and other finite data structures, which\nresults in certain problems that could be better represented by iterators being expressed in Arrays,\nor using libraries to introduce the necessary helpers. Many [libraries and languages](#prior-art--userland-implementations) already provide these interfaces.\n\n## Proposal\n\nThe proposal introduces a collection of new methods on the Iterator prototype, to allow general usage and consumption of iterators. For specifics on the implemented methods, please refer to the specification.\n\nSee [DETAILS.md](./DETAILS.md) for details on semantics decisions.\n\nSee this proposal rendered [here](https://tc39.es/proposal-iterator-helpers)\n\n## Added Methods\n\nFor Iterators we add the following methods:\n\n### `.map(mapperFn)`\n\n`map` takes a function as an argument. It allows users to apply a function to every element returned from an iterator.\n\nReturns an iterator of the values with the map function applied.\n\n#### Example\n\n```JavaScript\nfunction* naturals() {\n  let i = 0;\n  while (true) {\n    yield i;\n    i += 1;\n  }\n}\n\nconst result = naturals()\n  .map(value =\u003e {\n    return value * value;\n  });\nresult.next(); //  {value: 0, done: false};\nresult.next(); //  {value: 1, done: false};\nresult.next(); //  {value: 4, done: false};\n```\n\n### `.filter(filtererFn)`\n\n`filter` takes a function as an argument. It allows users to skip values from an iterator which do not pass a filter function.\n\nReturns an iterator of values from the original iterator that pass the filter.\n\n#### Example\n\n```JavaScript\nfunction* naturals() {\n  let i = 0;\n  while (true) {\n    yield i;\n    i += 1;\n  }\n}\n\nconst result = naturals()\n  .filter(value =\u003e {\n    return value % 2 == 0;\n  });\nresult.next(); //  {value: 0, done: false};\nresult.next(); //  {value: 2, done: false};\nresult.next(); //  {value: 4, done: false};\n```\n\n### `.take(limit)`\n\n`take` takes an integer as an argument. It returns an iterator that produces, at most, the given number of elements produced by the underlying iterator.\n\nReturns an iterator with items from the original iterator from 0 until the limit.\n\n#### Example\n\n```JavaScript\nfunction* naturals() {\n  let i = 0;\n  while (true) {\n    yield i;\n    i += 1;\n  }\n}\n\nconst result = naturals()\n  .take(3);\nresult.next(); //  {value: 0, done: false};\nresult.next(); //  {value: 1, done: false};\nresult.next(); //  {value: 2, done: false};\nresult.next(); //  {value: undefined, done: true};\n```\n\n### `.drop(limit)`\n\n`drop` takes an integer as an argument. It skips the given number of elements produced by the underlying iterator before itself producing any remaining elements.\n\nReturns an iterator of items after the limit.\n\n#### Example\n\n```JavaScript\nfunction* naturals() {\n  let i = 0;\n  while (true) {\n    yield i;\n    i += 1;\n  }\n}\n\nconst result = naturals()\n  .drop(3);\nresult.next(); //  {value: 3, done: false};\nresult.next(); //  {value: 4, done: false};\nresult.next(); //  {value: 5, done: false};\n```\n\n### `.flatMap(mapperFn)`\n\n`.flatMap` takes a mapping function as an argument. It returns an iterator that produces all elements of the iterators produced by applying the mapping function to the elements produced by the underlying iterator.\n\nReturns an iterator of flat values.\n\n#### Example\n\n```JavaScript\nconst sunny = [\"It's Sunny in\", \"\", \"California\"].values();\n\nconst result = sunny\n  .flatMap(value =\u003e value.split(\" \").values());\nresult.next(); //  {value: \"It's\", done: false};\nresult.next(); //  {value: \"Sunny\", done: false};\nresult.next(); //  {value: \"in\", done: false};\nresult.next(); //  {value: \"\", done: false};\nresult.next(); //  {value: \"California\", done: false};\nresult.next(); //  {value: undefined, done: true};\n```\n\n### `.reduce(reducer [, initialValue ])`\n\n`reduce` takes a function and an optional initial value as an argument. It allows users to apply a function to every element returned from an iterator, while keeping track of the most recent result of the reducer (the memo). For the first element, the given initial value is used as the memo.\n\nReturns a value (in the example, a number) of the type returned to the reducer function.\n\n#### Example\n\n```JavaScript\nfunction* naturals() {\n  let i = 0;\n  while (true) {\n    yield i;\n    i += 1;\n  }\n}\n\nconst result = naturals()\n  .take(5)\n  .reduce((sum, value) =\u003e {\n    return sum + value;\n  }, 3);\n\nresult // 13\n```\n\n### `.toArray()`\n\nWhen you have a non-infinite iterator which you wish to transform into an array, you can do so with\nthe builtin `toArray` method.\n\nReturns an Array containing the values from the iterator.\n\n#### Example\n\n```JavaScript\nfunction* naturals() {\n  let i = 0;\n  while (true) {\n    yield i;\n    i += 1;\n  }\n}\n\nconst result = naturals()\n  .take(5)\n  .toArray();\n\nresult // [0, 1, 2, 3, 4]\n```\n\n### `.forEach(fn)`\n\nFor using side effects with an iterator, you can use the `.forEach` builtin method, which takes as\nan argument a function.\n\nReturns undefined.\n\n#### Example\n\n```JavaScript\nconst log = [];\nconst fn = (value) =\u003e log.push(value);\nconst iter = [1, 2, 3].values();\n\niter.forEach(fn);\nconsole.log(log.join(\", \")) // \"1, 2, 3\"\n```\n\n### `.some(fn)`\n\nTo check if any value in the iterator matches a given predicate, `.some` can be used. It takes as an argument a function which returns true or false.\n\n\nReturns a boolean which is true if any element returned true when `fn` was called on it. The\niterator is consumed when some is called.\n\n#### Example\n\n```JavaScript\nfunction* naturals() {\n  let i = 0;\n  while (true) {\n    yield i;\n    i += 1;\n  }\n}\n\nconst iter = naturals().take(4);\n\niter.some(v =\u003e v \u003e 1); // true\niter.some(v =\u003e true); // false, iterator is already consumed.\n\nnaturals().take(4).some(v =\u003e v \u003e 1); // true\nnaturals().take(4).some(v =\u003e v == 1); // true, acting on a new iterator\n```\n\n### `.every(fn)`\n\n`.every` takes a function which returns a boolean as an argument. It is used to check if every\nvalue generated by the iterator passes the test function.\n\nReturns a boolean.\n\n```JavaScript\nfunction* naturals() {\n  let i = 0;\n  while (true) {\n    yield i;\n    i += 1;\n  }\n}\n\nconst iter = naturals().take(10);\n\niter.every(v =\u003e v \u003e= 0); // true\niter.every(v =\u003e false); // true, iterator is already consumed.\n\nnaturals().take(4).every(v =\u003e v \u003e 0); // false, first value is 0\nnaturals().take(4).every(v =\u003e v \u003e= 0); // true, acting on a new iterator\n```\n\n### `.find(fn)`\n\n`.find` takes a function as an argument. It is used to find the first element in an iterator that matches.\n\nCan be used without `take` on infinite iterators.\n\nReturns the found element, or *undefined* if no element matches `fn`.\n\n```JavaScript\nfunction* naturals() {\n  let i = 0;\n  while (true) {\n    yield i;\n    i += 1;\n  }\n}\n\nnaturals().find(v =\u003e v \u003e 1); // 2\n```\n\n### `Iterator.from(object)`\n\n`.from` is a _static_ method (unlike the others listed above) which takes an object as an argument. This method allows wrapping \"iterator-like\" objects with an iterator.\n\nReturns the object if it is already an iterator, returns a wrapping iterator if the passed object\nimplements a callable @@iterator property.\n\n```JavaScript\nclass Iter {\n  next() {\n    return { done: false, value: 1 };\n  }\n}\n\nconst iter = new Iter();\nconst wrapper = Iterator.from(iter);\n\nwrapper.next() // { value: 1, done: false }\n```\n\n## Iterator helpers and the generator protocol\n\nThe generator protocol facilitates coordination between a producer and a\nconsumer, which is necessarily broken by iteration-based transforms. There is\nno way to properly preserve or re-establish this coordination. We've taken the\nphilosophy that any iterators produced by the helpers this proposal adds only\nimplement the iterator protocol and make no attempt to support generators which\nuse the remainder of the generator protocol. Specifically, such iterators do\nnot implement `.throw` and do not forward the parameter of `.next` or `.return`\nto an underlying or \"source\" iterator.\n\n\n#### Extending Iterator Prototype\n\nWith this proposal, it will be easier to extend the IteratorPrototype for a custom class. See the\nbelow example for the previous implementation compared to the new one.\n\n```js\nconst MyIteratorPrototype = {\n  next() {},\n  throw() {},\n  return() {},\n\n  // but we don't properly implement %IteratorPrototype%!!!\n};\n\n// Previously...\n// Object.setPrototypeOf(MyIteratorPrototype,\n//   Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())));\n\nObject.setPrototypeOf(MyIteratorPrototype, Iterator.prototype);\n```\n\n## Q \u0026 A\n\n### Why not use Array.from + Array.prototype methods?\n\nAll of the iterator-producing methods in this proposal are **lazy**. They will\nonly consume the iterator when they need the next item from it. Especially\nfor iterators that never end, this is key. Without generic support for\nany form of iterator, different iterators have to be handled differently.\n\n### How can I access the new intrinsics?\n\n```js\nconst IteratorHelperPrototype = Object.getPrototypeOf(Iterator.from([]).take(0));\nconst WrapForValidIteratorPrototype = Object.getPrototypeOf(Iterator.from({ next(){} }));\n```\n\n## Prior Art \u0026 Userland implementations\n\n- https://www.npmjs.com/package/itertools\n- https://www.npmjs.com/package/lodash\n- https://docs.python.org/3/library/itertools.html\n- https://github.com/more-itertools/more-itertools\n- https://docs.rs/itertools/\n- https://doc.rust-lang.org/std/iter/trait.Iterator.html\n- https://www.boost.org/doc/libs/1_66_0/libs/iterator/doc/index.html\n- https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable\n- https://github.com/ReactiveX/IxJS\n- https://www.npmjs.com/package/ballvalve\n- https://github.com/zloirock/core-js#iterator-helpers\n- Node.js [Readable](https://nodejs.org/api/stream.html#readable-streams) streams implement this proposal in its entirety.\n\n\n| Method                      | Rust | Python | npm Itertools | C# |\n| --------------------------- | ---- | ------ | --------------| -- |\n| all                         | ☑    | ☑      | ☑             | ☑  |\n| any                         | ☑    | ☑      | ☑             | ☑  |\n| chain                       | ☑    | ☑      | ☑             | ☑  |\n| collect                     | ☑    | ☐      | ☐             | ☐  |\n| count                       | ☑    | ☑      | ☑             | ☑  |\n| cycle                       | ☑    | ☑      | ☑             | ☐  |\n| enumerate                   | ☑    | ☑      | ☑             | ☐  |\n| filter                      | ☑    | ☑      | ☑             | ☑  |\n| filterMap                   | ☑    | ☐      | ☐             | ☐  |\n| find                        | ☑    | ☐      | ☑             | ☑  |\n| findMap                     | ☑    | ☐      | ☐             | ☐  |\n| flatMap                     | ☑    | ☐      | ☑             | ☑  |\n| flatten                     | ☑    | ☐      | ☐             | ☐  |\n| forEach                     | ☑    | ☐      | ☐             | ☐  |\n| last                        | ☑    | ☐      | ☐             | ☑  |\n| map                         | ☑    | ☑      | ☑             | ☑  |\n| max                         | ☑    | ☑      | ☑             | ☑  |\n| min                         | ☑    | ☑      | ☑             | ☑  |\n| nth                         | ☑    | ☐      | ☐             | ☑  |\n| partition                   | ☑    | ☐      | ☐             | ☑  |\n| peekable                    | ☑    | ☐      | ☐             | ☐  |\n| position                    | ☑    | ☐      | ☐             | ☐  |\n| product                     | ☑    | ☑      | ☐             | ☐  |\n| reverse                     | ☑    | ☑      | ☐             | ☑  |\n| scan                        | ☑    | ☐      | ☐             | ☐  |\n| skip                        | ☑    | ☐      | ☐             | ☑  |\n| skipWhile                   | ☑    | ☑      | ☐             | ☑  |\n| stepBy                      | ☑    | ☐      | ☐             | ☐  |\n| sum                         | ☑    | ☑      | ☑             | ☑  |\n| take                        | ☑    | ☐      | ☑             | ☑  |\n| takeWhile                   | ☑    | ☑      | ☐             | ☑  |\n| unzip                       | ☑    | ☑      | ☑             | ☐  |\n| zip                         | ☑    | ☑      | ☑             | ☑  |\n| compress                    | ☐    | ☑      | ☑             | ☐  |\n| permutations                | ☐    | ☑      | ☑             | ☐  |\n| repeat                      | ☑    | ☑      | ☑             | ☑  |\n| slice                       | ☐    | ☑      | ☑             | ☐  |\n| starmap                     | ☐    | ☑      | ☐             | ☐  |\n| tee                         | ☐    | ☑      | ☐             | ☐  |\n| compact                     | ☐    | ☐      | ☑             | ☐  |\n| contains                    | ☐    | ☑      | ☑             | ☑  |\n| range                       | ☑    | ☑      | ☑             | ☑  |\n| reduce                      | ☑    | ☑      | ☑             | ☑  |\n| sorted                      | ☐    | ☑      | ☑             | ☐  |\n| unique                      | ☐    | ☐      | ☑             | ☑  |\n| average                     | ☐    | ☐      | ☐             | ☑  |\n| empty                       | ☑    | ☐      | ☐             | ☑  |\n| except                      | ☐    | ☐      | ☐             | ☑  |\n| intersect                   | ☐    | ☐      | ☐             | ☑  |\n| prepend                     | ☐    | ☐      | ☐             | ☑  |\n| append                      | ☐    | ☐      | ☐             | ☑  |\n\nNote: The method names are combined, such as `toArray` and `collect`.\n","funding_links":[],"categories":["HTML"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftc39%2Fproposal-iterator-helpers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftc39%2Fproposal-iterator-helpers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftc39%2Fproposal-iterator-helpers/lists"}