"Convert forEach to for-of" breaks with Maps (refactoring does not examine type of operand) #485
Labels
🐛 Bug
Refactoring breaks existing behavior
🙅 Require better TypeChecker
This refactoring would need Abracadabra to determine types faster and better than it can do
Describe the bug
The "convert forEach to for-of" appears to act blindly on a pattern-matching basis, but not all
.forEach()
methods are created equal! For example, Maps have a forEach method with a different callback signature. Refactoringmap.forEach(value => { ...
tofor(const value of map) { ...
will break code!How to reproduce
With this code:
Perform the "convert forEach to for-of" action on
animalPowerLevels.forEach
. The resulting code will look like this:...which in TypeScript results in the following error:
This happens since
for-of
for Maps iterates over key-value pairs.Expected behavior
"Convert forEach to for-of" should take the type of the operand into account, where possible. For the above example, these would be acceptable results:
With the latter being preferred in the case where only the value was being used (ie.
Map.forEach
with a single-argument callback).In the case where
Map.forEach
is called with a two-argument callback, like this:The expected result would be this:
Additional information
v6.9.1
I haven't checked, but there may be other built-ins with
forEach
methods that will result in broken code if this refactoring is applied to them.Also, arguably this refactoring should not work based on simple pattern matching in the first place. Anything that's not a built-in but that has a
forEach
method should probably not be refactorable with this action -- the action should only work for built-ins. Even assuming other objects withforEach
methods have[@@iterator]
defined and are iterable withfor-of
, there's no guarantee the semantics would be the same -- theforEach
callback arg and the iterable values could be totally unrelated for userland code.The text was updated successfully, but these errors were encountered: