eslint-plugin-unicorn
eslint-plugin-unicorn copied to clipboard
Rule proposal: `proper-object-iterable-methods`
Fail
// Should use `Object.values`
for (const key of Object.keys(foo)) {
bar(foo[key]);
}
// Should use `Object.entries`
for (const key of Object.keys(foo)) {
bar(foo[key], key);
}
// Should use `Object.values`
const foo = Object.keys(bar).map(key => baz(bar[key]));
// Should use `Object.entries`
const foo = Object.keys(bar).map(key => baz(bar[key], key));
// Should use `Object.keys`
for (const [key] of Object.entries(foo)) {
bar(key);
}
Pass
for (const key of Object.keys(foo)) {
foo[key] = 'new value';
delete foo[key];
foo[key]++;
}
Rule name: prefer-object-entries-or-values
? Any better suggestions? Or should it be split into two rules?
I think we should also enforce Object.keys
over Object.entries
in this case
for (const [key] of Object.entries(foo)) {
bar(key);
}
So better come up a better name cover all them.
proper-object-iterable-methods
?
proper-object-iterable-methods?
Yeah. Sounds ok. I cannot come up with something better.
This is now accepted.
a (presumably) more complicated case that could also be detected:
// fail
const foo = Object.keys(myObj).reduce((acc, key) => {
const value = myObj[key];
acc[key] = value + 1;
return acc;
}, {})
// pass
const foo = Object.fromEntries(
Object.entries(myObj).map(([key, value]) => [key, value + 1])
)
While I was doing a refactoring to get rid of a for..in
. I wondered if this rule should handle this case
// BEFORE
for (const key in object) {
const value = object[key]
f(value)
}
// AFTER
for (const [key, value] of Object.entries(object)) {
f(value)
}
Object.entries()
is the same as iterating with afor...in
loop, except that afor...in
loop enumerates properties in the prototype chain as well.
The answer is no. This transformation is not generally equivalent. This transformation is only valid for plain objects.
@Pyrolistical presumably you also have the guard-for-in
rule so:
- the "before" version should not exist
- the gated version should be equivalent and thus fixable
@fregante for..in
is safe if you know its an object literal. I don't use classes, but you are right this can cause problems to those who do.
> for (const key in {x: 42}) { console.log(key) }
x
for..in is safe if you know its an object literal.
No, it's not.
Object.prototype.map = () => {}
for (const key in {x: 42}) { console.log(key) }
<script src="lib-add-method-to-object-prototype-but-forgot-set-non-enumerable.js">
import "lib-add-method-to-object-prototype-but-forgot-set-non-enumerable"