Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow rest/spread on polyfilled or builtin iterables without Symbol support #11268

Merged
merged 2 commits into from Mar 17, 2020

Conversation

nicolo-ribaudo
Copy link
Member

@nicolo-ribaudo nicolo-ribaudo commented Mar 15, 2020

Q                       A
Fixed Issues? Fixes #9277
Patch: Bug Fix? Yes
Major: Breaking Change?
Minor: New Feature?
Tests Added + Pass? Yes
Documentation PR Link
Any Dependency Changes?
License MIT

Currently, when Symbol is not supported, we allow using rest/spread with:

  • arrays
  • strings
  • arguments

With this PR, it will be also possible to use it with

  • maps
  • sets
  • binary arrays

While in old browsers es6 builtins would still need to be polyfilled, it's way
easier to polyfill them because Symbol cannot be reliably polyfilled.

I didn't use instanceof because:

  • it doesn't work with polyfills not attached to the global scope
  • when using Babel to load polyfills, it would force the inclusion of Map and Set polyfills even if they are not used

Downside: the current approach of relying on toString || construcor.name doesn't work with subclasses.


Depends on #11264 (mostly to avoid merge conflicts, it shouldn't be a problem because the other PR is straightforward).
I'm marking this as a draft until that PR is merged, but this is ready for review.

@nicolo-ribaudo nicolo-ribaudo added the PR: Bug Fix 🐛 A type of pull request used for our changelog categories label Mar 15, 2020
@nicolo-ribaudo nicolo-ribaudo added this to Blocked in Iterables DX Mar 15, 2020
if (!o) return;
if (typeof o === "string") return Array.from(o);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should work with es6-shim. As an alternative, we could detect the presence of a _es6-shim iterator_ property.

I'm thinking specifically about es6-shim because it's the polyfill with most downloads on npm after core-js, and core-js's future is uncertain.

Copy link
Member

@ljharb ljharb Mar 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By using Array.from, it already works with es6-shim without having to hardcode anything.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Array.from is not supported on IE11. Can we use arrayLikeToArray?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that Maps and Sets are not array-like.
I decided to use Array.from because because it is way more easily polyfilled than symbols.

WDYT about using arrayLikeToArray for strings/arguments/binary arrays, and Array.from for Map/Set?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's included with es6-shim tho, and imo it's completely reasonable to require anything faithfully polyfillable/shimmable, but symbols are not that.

@nicolo-ribaudo's suggestion works for me as well.

@ljharb
Copy link
Member

ljharb commented Mar 15, 2020

My es-get-iterator and iterate-value packages may help here - they work on every version of every browser and node, and are also tested with es6-shim, core-js 2, and core-js 3.

@nicolo-ribaudo
Copy link
Member Author

@ljharb I would prefer to avoid loading them because they can't be easily inlined (when not using @babel/runtime) and are way bigger than the helper I implemented in this PR.

I think that we should see if this fix is "good enough", and if we get other bug reports we can iterate.

@nicolo-ribaudo nicolo-ribaudo moved this from Blocked to Ready for review in Iterables DX Mar 16, 2020
…supported

Currently, when `Symbol` is not supported, we allow using rest/spread with:
- arrays
- strings
- arguments

With this PR, it will be also possible to use it with
- maps
- sets
- binary arrays

While in old browsers es6 builtins would still need to be polyfilled, it's way
easier to polyfill them because `Symbol` cannot be reliably polyfilled.

I didn't use `instanceof` becase:
- it doesn't work with polyfills not attatched to the global scope
- when using Babel to load polyfills, it would force the inclusion of `Map` and `Set` polyfills even if they are not used

Downside: the current approach of relying on `toString || construcor.name` doesn't work with subclasses.
@nicolo-ribaudo nicolo-ribaudo marked this pull request as ready for review March 16, 2020 23:51
@nicolo-ribaudo nicolo-ribaudo changed the base branch from iterables-dx/rest-spread-better-error-messages to master March 17, 2020 00:57
if (typeof o === "string") return arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(n);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicolo-ribaudo This should really be

    if (n === "Map" || n === "Set") return Array.from(o);

because n is a string!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
outdated A closed issue/PR that is archived due to age. Recommended to make a new issue PR: Bug Fix 🐛 A type of pull request used for our changelog categories
Projects
No open projects
Iterables DX
  
Done
Development

Successfully merging this pull request may close these issues.

Spread transformation requires Symbol.iterator now
5 participants