Skip to content

iterators with ES5 target #4031

Description

This is related to #3164 which implies that TypeScript will NEVER support using generic iterators when the target is ES5. I understand that supporting this requires design tradeoffs that the team wants to avoid. However, if this is not done, it's difficult to see how TypeScript can be considered a serious alternative to Babel and Traceur for ES6 support. It will be a long time (2 years?) until most web apps will have as their minimum browser requirement only browsers that support ES6 iterators. I really think the direction presented in issue 3164 needs to be reconsidered.

Activity

  1. s-panferov commented on Jul 27, 2015

    @s-panferov

    can be considered a serious alternative

    Mark Volkmann (@mvolkmann) just want to ask why they must be alternatives? You easily create TS(es6) -> Babel -> es5 pipeline with such tools as webpack.

  2. mvolkmann commented on Jul 27, 2015

    @mvolkmann
    Author

    Yeah, I considered that option and even tried it to verify that it works. However, I don't think that's an acceptable solution for development on medium to large projects. I would increase build times too much.

    I think TypeScript should aim to be a complete solution for transpiling ES6 to ES5.

  3. wgebczyk commented on Jul 27, 2015

    @wgebczyk

    true, complete transpiler instead of multiple packages for packages for packages...

  4. wgebczyk commented on Jul 28, 2015

    @wgebczyk

    I understand that some might want not to generate something for ES5.

    Maybe we could introduce "conversion levels/tiers".
    Tier1: everything is converted to make it work on designated ESx
    Tier2: if feature from this level or Tier3 is used, then generate code for that, otherwise error+quit
    Tier3: if feature from this level is used, then generate code for that, otherwise error+quit
    TierN: if target ESx does not support used feature, raise error and stop code generation

    or have some enumerated switch "--features:iterator;arrow;bow;star;moon;etc" that defines what features should be polyfiled.

    What do you think?

  5. kitsonk commented on Jul 28, 2015

    @kitsonk
    Contributor

    Personally, I don't want TypeScript solving all this stuff for me. Especially polyfilling can have huge negative consequences when you are running other scripts in an environment. Anyone who has complete control of the code running in the their runtime environment on their page hasn't either worked on a big enough project or is part of a small company organisation. I have actually seen instances where you have had to feature detect a native implementation or not because the polyfill isn't "quite" the same as the real thing.

    Some stuff is impossible to fully polyfill too, for example subclassing Arrays in ES5 is impossible. WeakMap was impossible until .clear() was removed from the spec. TypeArrays, forget it!

    I would rather encapsulate functionality and offload it to native implementations if present, with the possibility in my toolchain.

    What would benefit though, instead of TypeScript solving everything, is that there was a coherent "plug-in" architecture which allowed me easier access at compile time, to the AST, which I could provide code which handles the emit. That way, if I chose to polyfill some of functional ES6 code, versus the language constructs, I could.

    TypeScript polyfilling all the ES6/ES7 functionality will end in tears for TypeScript and I am glad the team have resisted it.

  6. wgebczyk commented on Jul 28, 2015

    @wgebczyk

    From my point of view, hen you write TS:

    func(aaa => aaa.toString());
    

    and when targeting ES5 you get something like:

    func(function(aaa) { return aaa.toString(); });
    

    So right now TS generates code for non existing functionality. Why not generate that for other features?

    I respect that from perspective of person that has years of JS experience and tooling and chaining and knowing all tricks and browser inconsistencies, generating selectively might sense.

    There are other people that might expect that TS will hide those inconsistencies and focus on code of higher level than pure JS.

    I don't want to jump into "solution" that requires packages for packages for package managers for packages. I've stumbled into "framework" Aurelia", where Hello World on HDD took about 160MB!!! 2-3 package managers and tons of packages to compile that... INSANE!

    Part of a lot of issues is effect of lack of clear TS team vision, what and how features will be done and considered to be implemented or not. Some features are added because there is buzz around them (like type/import/var and none works as advertised).

  7. danquirk commented on Jul 28, 2015

    @danquirk
    Member

    Part of a lot of issues is effect of lack of clear TS team vision, what and how features will be done and considered to be implemented or not. Some features are added because there is buzz around them (like type/import/var and none works as advertised).

    Wojciech Gebczyk (@wgebczyk) could you be more specific about what you're finding lacking here? We've tried to be fairly transparent with our plans in a formal way at https://github.com/Microsoft/TypeScript/wiki/Roadmap beyond just manually tracking what's going on on the repo here. Likewise we've tried to enumerate some of our design philosophy here https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals.

    As far as type/import/var, maybe a separate thread/issue would be useful if you're finding they're not meeting your needs.

  8. kitsonk commented on Jul 28, 2015

    @kitsonk
    Contributor

    Wojciech Gebczyk (@wgebczyk) actually, lambdas are more complicated then that... When accessing the canonical this within the function, TypeScript has to emit something else to give access to the canonical this:

    (() => {
        this.foo = 'bar'
    })();

    Gets emitted as:

    var _this = this;
    (function () {
        _this.foo = 'bar';
    })();

    And lots of ES6 and ES7 are far more complicated than that. It is a big rabbit hole...

    Pollyfilling all of ES6 isn't what TypeScript is about. Making JavaScript/ES more "safe" by strong typing and published guarded interfaces is what I like about TypeScript and what I think it is good at. You can write functional polyfills/shims on top of TypeScript quite easily, for example Promises and WeakMaps.

  9. mvolkmann commented on Jul 28, 2015

    @mvolkmann
    Author

    Okay, just to be clear it sounds like what is meant by saying that TypeScript is a superset of ES6 is that it will support any ES6 features that the runtime environment (browser, Node.js, ...) supports.

    Using that logic maybe any current transpiling it does (ex. arrow functions) should be removed.

    That's not what I want. I don't want to have to rely on another tool for transpiling to ES5.

  10. jonaskello commented on Dec 27, 2015

    @jonaskello

    +1. I can see from the argument from a theoretical standpoint that TS should not have polyfills. But from a practical standpoint I think most users just want idiomatic ES6 constructs to work out-of-the box with TS and not resort to double compiling with Babel or some other transpiler. (And I'm counting iterating a Map or Set with for-of loops as idiomatic in ES6).

    Why not have a mode that compiles to ES5 but requires the user to provide his own polyfill for any ES6 API that the TS compiler does not handle? AFAIK Babel does it this way and it works very well.

  11. saschanaz commented on Dec 28, 2015

    @saschanaz
    Contributor

    I hope we get some way to know a type has an iterator or not. From #4947:

    Introduce a ES5-compatible way to declare iterable interfaces (Similar to what discussed in #2862)

    interface NodeList iterable<Node> {}

    iterable in ES6 mode will work as a shorthand of [Symbol.iterator](): IterableIterator<T> but in ES5 mode will just make an internal flag to be allowed in for-of loop.

    // NodeList is marked as iterable,
    // it has .length property and index signature for ES5 emit, so all good
    for (let node of document.querySelectorAll("...")) {
    }

    This will make it work both on ES5 and ES6 without changing emit.

  12. amir-arad commented on Jan 11, 2016

    @amir-arad

    a big +1 on Jonas Kello (@jonaskello) 's suggestion.
    now I'm off to convert my beautiful useless Iterable API into something that eagerly creates long arrays on every invocation, so that it can be used in for ... of loops.
    😞

  13. alexanderharm commented on Feb 16, 2016

    @alexanderharm

    I totally second Mark Volkmann (@mvolkmann) considering that libraries like Angular2 and Immutable.js embrace the for ... of loop construct. I would expect that setting "target": "es5" actually results in ES5 and not having to verify that (arrow functions: check, for ... of loops: duh, ...). Right now I even have to find out the hard way since documentation is missing (https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#5.7)

  14. BowserKingKoopa commented on May 30, 2016

    @BowserKingKoopa

    I just smacked into this issue. I'm unable to get TypeScript to iterate over an Iterator with for...of. I get "x is not an array type or a string type."

  15. fluffywaffles commented on Jul 1, 2016

    @fluffywaffles

    Would it be possible to enable the transpilation of for..of when targeting ES5 in tsconfig.json?

    Something like, "enableForOfTranspilation": true - with the caveat that it will be slower, and requiring that you must have imported typings and a polyfill for Symbol in order to compile. I believe checking for typings for Symbol, and whether it is imported in your source either globally or as a module, is already done by tsc - but it would still require some work to perform the actual transpilation.

    I am using TypeScript with Core.js, and so the Symbol polyfill is already a part of my project. This is clear from my tsconfig, seeing as I include core.js typings in order for my code to type check.

    It appears to me that Mohamed Hegazy (@mhegazy)'s list of reasons in #3164 are largely centered on possible performance implications. It is noteworthy Angular 2's ngFor does not allow for..of loops over Maps, Objects, etc., so perhaps this is actually an onerous undertaking or they would already have asked for it in TS / done it themselves - but if it can be reasonably implemented, I'd like to have the option.

    Additionally, creating a "pipeline" whereby you transpile TS -> ES6 -> ES5 with Babel as a middleman is undesirable for obvious reasons, not least of which being the much higher compilation time incurred by compiling twice.

  16. fluffywaffles commented on Jul 1, 2016

    @fluffywaffles

    Also of note, the following compiles and works (possibly only with polyfills, but still):

    for (let [ key, value ] of Array.from(myMap.entries())) { ... }

    This is an acceptable workaround for me.

  17. added
    FixedA PR has been merged for this issue
    and removed on Feb 17, 2017
  18. mhegazy commented on Feb 17, 2017

    @mhegazy
    Contributor

    Should be addressed by #12346, with --downlevelIteration.

  19. locked and limited conversation to collaborators on Jun 19, 2018
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

    FixedA PR has been merged for this issueSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions