镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

for-of does not work with some DOM collections when target is ES6 #2695

Description

@Arnavion

Update: This issue is now only for the following collections:

  • MediaList
  • StyleSheetList
  • CSSRuleList

Originally it was about NodeList as well, but that was fixed (along with DOMTokenList) in #3393


Original:

var paragraphs = document.querySelectorAll("p");
for (let p of paragraphs) {
    console.log(p);
}
foo.ts(2,15): error TS2488: The right-hand side of a 'for...of' statement must have a '[Symbol.iterator]()' method that returns an iterator.

Seems it just needs an update to lib.es6.d.ts to add the [Symbol.iterator()] to all the collections that have an indexer and length property. The ones I found that have it in Nightly are below. The rest were either IE-only or didn't exist. Removed my list since it seems FF has more than the specs allow. See zloirock/core-js#137 (comment) for a more accurate list.

Activity

  1. mhegazy commented on Apr 9, 2015

    @mhegazy
    Contributor

    Zhengbo Li (@zhengbli) would this be covered in your change?

  2. Arnavion commented on Apr 9, 2015

    @Arnavion
    ContributorAuthor

    (This would also require making two versions of dom.d.ts - for ES5 and ES6.)

  3. mhegazy commented on Apr 9, 2015

    @mhegazy
    Contributor

    yup. that is correct.

  4. djarekg commented on Apr 30, 2015

    @djarekg

    This should also be supported in ES3/ES5 since the emitted loop is just looping over the indexes.

  5. mhegazy commented on Apr 30, 2015

    @mhegazy
    Contributor

    iterators relay on symbols and these are defined in ES6. I think what we need is to allow iterating ArrayLike in ES3/ES5 (#2862).

  6. Arnavion commented on May 1, 2015

    @Arnavion
    ContributorAuthor

    Dustin Griffith (@djarekg) That is not correct. It can also require converting NodeList to an array first (with slice) to handle the livelist getting modified during iteration. See #2696

  7. NekR commented on May 31, 2015

    @NekR

    Please do not forget to include in this list TouchList interface. Thanks.

  8. mhegazy commented on Jun 9, 2015

    @mhegazy
    Contributor

    Kagami Sascha Rosylight (@saschanaz) has added support for:

    • NodeList
    • NodeListOf
    • DOMTokenList

    The other interfaces do not seem to be iterable in the spec. Arnav Singh (@Arnavion) any ideas?

  9. Arnavion commented on Jun 9, 2015

    @Arnavion
    ContributorAuthor

    They're not iterable<> but they are ArrayClass, eg CSSRuleList. That means their prototype is supposed to be an Array instead of Object and so they have all the properties of Array including [Symbol.iterator], although no browser has actually gone that far, not even Nightly.

    NodeList is also supposed to be ArrayClass instead of iterable<>, but Chrome had problems with it and (temporarily?) abandoned it. FF has an open bug to convert NodeList from iterable to ArrayClass but so far nothing has happened. I don't know what browsers' plan for these "ArrayClass" interfaces - I would guess it's likely that all ArrayClass interfaces will eventually be iterable even if they aren't full-blown Arrays.

    The array iterator Array.prototype[Symbol.iterator] is also usable for all DOM collections, and this is what Nightly does. For example, CSSRuleList.prototype[Symbol.iterator] === Array.prototype[Symbol.iterator] is true in Nightly. This is intentional - ArrayIterator is supposed to work with ArrayLikes. So even in browsers where DOM collection prototypes don't already have a Symbol.iterator property, assigning it with, say CSSRuleList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];, works and makes them iterable with for-of. This would be an argument for TS to allow for-of for these types. The user just needs to add a polyfill to assign the [Symbol.iterator] property on all the DOM list prototypes they're interested in iterating with for-of. But these will have to be custom polyfills - I don't know any polyfill library that adds Symbol.iterator properties to all DOM collections. Babel (core-js) does it but only for NodeList.

    On the other hand, Array.from() works for them since they are array-likes, and even in TS they implicitly extend ArrayLike<T> so Array.from()'s signature is not a problem. So that's an argument against allowing for-of for these types in TS.

    So basically, from the user's point of view, either they use a polyfill for Array.from, and use Array.from to convert all their DOM collections before using for-of. This requires no change from TS, and such a polyfill already exists. (Then there was no point to adding [Symbol.iterator] to NodeList either, but anyway...)

    Or, TS allows for-of with all DOM collections, and the user uses a polyfill that adds [Symbol.iterator] properties to all those collections. This does require change from TS, and such a polyfill doesn't already exist.

    I don't have an opinion either way.

  10. 48 remaining items

  11. saschanaz commented on Apr 24, 2018

    @saschanaz
    Contributor

    Keith Henry (@KeithHenry) That file should replace lib.dom.iterable.d.ts but the upstream does not yet support methods including entries(). Coming Soon™️, though!

  12. nevercast commented on May 7, 2018

    @nevercast

    What do you mean by upstream does not support, do you mean iterators, in general, are broken? or is this purely a type definition issue?

  13. saschanaz commented on May 7, 2018

    @saschanaz
    Contributor

    Ah, by upstream I mean this one.

  14. saschanaz commented on Nov 9, 2018

    @saschanaz
    Contributor

    This can be closed now as lib.dom.iterable.d.ts have iterators for MediaList, StyleSheetList, CSSRuleList, and many more.

  15. thany commented on Feb 5, 2019

    @thany

    This problem still exists for me when trying to iterate over NodeListOf<Element>. A NodeList is always iterable. Period.

    Some code:

    const triggers = element.querySelectorAll('.trigger');
    for (const trigger of triggers) {
        console.log(trigger);
    }

    The error is on triggers in VS Code, using typescript 3.2.2.

    The error:

    [ts] Type 'NodeListOf<Element>' is not an array type or a string type. [2495]
    

    Technically correct. A NodeList is indeed neither an array nor a string. But for..of works on a great many more kinds of objects, including NodeList.

    The above code compiles and works fine. So why complain about something that plainly isn't the case?

  16. saschanaz commented on Feb 5, 2019

    @saschanaz
    Contributor

    Martijn Saly (@thany) Ensure the target is ES6 or higher. Currently TS does not support for-of on general iterable objects when the target is ES5/ES3.

  17. RyanCavanaugh commented on Feb 5, 2019

    @RyanCavanaugh
    Member

    Or enable --downlevelIteration

  18. thany commented on Feb 11, 2019

    @thany

    First of all, why does TS need to support it at all? It just needs to output the transpiled JS and let JS handle whether the object can be looped over or not.

    Apart from that, NodeList is always iterable, in every browser. Some require a indexed for-loop, newer browser suport for..of. But either way the object can be looped over perfectly fine.

    If the target is ES5, produce a classic for-loop.
    If the target is ES6 or higher, produce a for..of loop.

    I don't see how this is complicated in any way.

  19. saschanaz commented on Feb 11, 2019

    @saschanaz
    Contributor

    Martijn Saly (@thany) Have you tried --downlevelIteration (introduced in TS2.3, I forgot about it 😅)? I think that should work.

  20. thany commented on Feb 12, 2019

    @thany

    I've enabled downlevelIteration (in our tsconfig.json) which doesn't produce any difference. The code still builds and works fine, but I still get the error in VS Code.

    Also since the update, VS Code has switched to TS 3.3.1, in case you didn't know.

  21. saschanaz commented on Feb 12, 2019

    @saschanaz
    Contributor
  22. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptDomain: lib.d.tsThe issue relates to the different libraries shipped with TypeScriptHelp WantedYou can do this

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions