Description
Before You File a Proposal Please Confirm You Have Done The Following...
- I have searched for related issues and found none that match my proposal.
- I have searched the current rule list and found no rules that match my proposal.
- I have read the FAQ and my problem is not listed.
My proposal is suitable for this project
- My proposal specifically checks TypeScript syntax, or it proposes a check that requires type information to be accurate.
- My proposal is not a "formatting rule"; meaning it does not just enforce how code is formatted (whitespace, brace placement, etc).
- I believe my proposal would be useful to the broader TypeScript community (meaning it is not a niche proposal).
Description
Using Object.values(...)
, Object.keys(...)
, Object.entries(...)
with a Map
object is a foot-gun because it will return empty []
regardless of the map contents and is most likely a mistake. These sorts of mistakes are easy to get into during refactors. This issue is spawning from a real-life refactor mistake -> element-hq/element-web#24995 (comment)
Related StackOverflow question: https://stackoverflow.com/questions/72315392/how-to-prevent-the-mistake-of-calling-object-values-on-a-map
As @bergus mentions from the SO question, it's possible to extend Map
to make a subclass that returns something with the object utilities but this seems a lot more niche compared to the big problem of running them on base Map
objects. AFAICT, it's not possible to use TypeScript on its own to catch this sort of thing because practically everything inherits from Object
and function arguments in TypeScript are contravariant (accepts supertypes but doesn't accept subtypes).
Fail Cases
const map = new Map([[ 1, 'one' ],[ 2, 'two' ]]);
// Rule would error for each of these usages, as using these object utilities
// on a Map will just return empty results and is probably a mistake
Object.keys(map); // -> []
Object.values(map); // -> []
Object.entries(map); // -> []
Pass Cases
const myObject = { 1: 'one', 2: 'two' };
Object.keys(myObject); // -> ['1', '2']
Object.values(myObject); // -> ['one', 'two']
Object.entries(myObject); // -> [[ 1, 'one' ],[ 2, 'two' ]]
const map = new Map([[ 1, 'one' ],[ 2, 'two' ]]);
map.keys(); // -> ['1', '2']
map.values(); // -> ['one', 'two']
map.entries(); // -> [[ 1, 'one' ],[ 2, 'two' ]]
Additional Info
No response