TypeScript: Spread operator is not correctly translated into JS
TypeScript Version: 1.8 Target: ES5
The following code:
[...(new Array(5))]
translates into:
(new Array(5)).slice();
However, the ES6 meaning is not the same. See the output below:
> [...(new Array(5))]
[ undefined, undefined, undefined, undefined, undefined ]
> (new Array(5)).slice();
[ , , , , ]
Expected behavior:
Array.apply(null, Array(5))
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 55
- Comments: 41 (17 by maintainers)
Commits related to this issue
- Feature/support ie11 (#139) * Change target to es2015 to support ie11 * Change tsconfig build target to es5 * Add downlevelIteration to compilerOptions to support ES5. Read more here: https://g... — committed to react-hook-form/react-hook-form by michaelbirchler 5 years ago
- Remove some redundant legacy code that turned sets to arrays. I will consult a friend to verify that I am not missing something obvious. Apparently it was probably a result of https://github.com/Micr... — committed to the-draupnir-project/Draupnir by Gnuxie 10 months ago
- Remove some redundant legacy code that turned sets to arrays. I will consult a friend to verify that I am not missing something obvious. Apparently it was probably a result of https://github.com/Micr... — committed to the-draupnir-project/Draupnir by Gnuxie 10 months ago
Is it going to be fixed?
I mean hey, it’s almost 3 years old.
My target is ES5 so not sure if this is related, but instances of
Setare incorrectly converted toslicewhen using the spread operator. According to the MDN docs (scroll down to the Relation with Array objects section) - I should be able to convert aSetinstance to an array by simply doing:But the TypeScript compiler converts
[...bar]tobar.slice()which is not correct.I’ve found that
Array.from(Set)works, but you need to make sure you have the typings installed.We ended up using Array.from() with the necessary typings and polyfills to make the spread operator work.
Then we are in situation when without
--downlevelIterationsome array (not other collections) operatin works and some simple emit wrong code. Again - wrong emitted code I consider as a bug. Examle:[...[1,2,3]] //emits correct code: [1,2,3]however
[...Array(5)] // emits broken code: Array(5).slice()How can I decide to enable
--downlevelIterationin case sometimes it works without it sometimes not?Shouldn’t compilator emit error for
[...Array(5)]in case--downlevelIterationis disabled instead of emitting wrong JS?@arackaf things have changed… when targeting ES5 the compiler supports downlevel iterator which is similar to the Babel feature which allows objects to expose an iterator interface.
Technically this issue was fixed by the addition to that feature and could be closed.
Array.from converts the iterable into an array.
The code
[...iterable]should be translated into the equivalent ofArray.from(iterable)as by definition[...iterable]translates the iterable into the array, just like the Array.from method.For example typescript (without the flag mentioned above) would translate
[...'abcdefg']into'abcdefg'.slice()instead ofArray.from('abcdefg')which both produce different outputs, and only the latter is spec-compliant@aik-jahoda when using
--downlevelIterationall iterators are spec compliant, so again, this could be closed, though it requires used of--downlevelIteration:@marvinhagemeister it requires that a global
Symbolpolyfill to be available at the runtime environment and that any iterables expose an iterable interface “symbol”. Because of those pre-reqs, I think the core team would be reticent to make it a default.Awesome, didn’t know about that flag. Perhaps
--downlevelIterationcan be directly included when setting the target toES5? Without knowing the reasons behind making it a specific flag it seems like that’d be a good default setting.@huy-nguyen the playground is always targets ES5 and does not include the optional
--downlevelIterationflag.You could not have encountered this error if you were targeting ES6, as the down emit described above would only occur when targeting ES5. I get the following when I run it through
tsc:I also get no error and the following output when using the
--downlevelIteration:This of course requires a global polyfill for
Map()andSymbolat run-time.This just bit us when dealing with a DOMStringList. The most common advice for converting DOMStringList to Array is to use
[...stringlist]but TypeScript compiles that tostringlist.slice()andsliceisn’t defined on DOMStringList.I believe
Array.prototype.slice.call(stringlist)would work for this particular case@brettjurgens This issue is about spread operator downlevel emit for arrays with holes. Your issue is #2696
Perhaps the emit should use
concatinstead ofslice😕 🌹