@studnicky/prefer-collection-types
Flags four patterns where arrays or plain objects perform worse than Set or Map:
- Pattern A: Inline array literal membership using
.includes()or anindexOf()comparison — usenew Set([...]).has(value). - Pattern B: An
Object.fromEntries()result accessed through computed brackets, directly or through aconstbinding — usenew Map(pairs).get(key). - Pattern C: A
constarray used exclusively for.includes()orindexOf()membership tests, in any scope — declare it asnew Set(...). - Pattern D: Array literal
.includes()inside.filter(),.some(),.every(),.find(), or.findIndex()callbacks — convert the array to aSet.
Set.has is 29× faster than Array.includes on equal-size inputs.
The rule recognizes membership-style indexOf() comparisons in any of their equivalent forms: x.indexOf(y) !== -1, x.indexOf(y) === -1 (negated), x.indexOf(y) > -1, x.indexOf(y) < 0, and x.indexOf(y) >= 0 (negated). Each of these is treated the same as an .includes() call for Patterns A and C.
Fixable: No · Options: checkArrayLiterals, checkFromEntries, checkModuleScopeArrays · Suggested severity: error
✗ Incorrect
ts
// Pattern A — inline array .includes()
if (["admin", "moderator", "owner"].includes(role)) {
/* ... */
}ts
// Pattern C — const array used only for membership checks
const VALID_METHODS = ["GET", "POST", "PUT", "DELETE"];
if (VALID_METHODS.includes(method)) {
/* ... */
}ts
// Pattern D — .includes() inside iteration callback
const active = users.filter((u) => ["active", "pending"].includes(u.status));ts
// Pattern B — Object.fromEntries accessed via computed key
const value = Object.fromEntries(pairs)[key];✓ Correct
ts
// Use Set for membership tests
if (new Set(["admin", "moderator", "owner"]).has(role)) {
/* ... */
}ts
// Module-scope Set
const VALID_METHODS = new Set(["GET", "POST", "PUT", "DELETE"]);
if (VALID_METHODS.has(method)) {
/* ... */
}ts
// Set inside iteration callback
const ACTIVE_STATUSES = new Set(["active", "pending"]);
const active = users.filter((u) => ACTIVE_STATUSES.has(u.status));ts
// Use Map instead of fromEntries + bracket access
const map = new Map(pairs);
const value = map.get(key);Options
json
{
"@studnicky/prefer-collection-types": [
"warn",
{
"checkArrayLiterals": true,
"checkFromEntries": true,
"checkModuleScopeArrays": true
}
]
}| Option | Type | Default | Description |
|---|---|---|---|
checkArrayLiterals | boolean | true | Flag inline array literals used with .includes() or membership-style indexOf() comparisons (Patterns A and D). |
checkFromEntries | boolean | true | Flag direct and const-bound Object.fromEntries() results accessed with computed bracket notation (Pattern B). |
checkModuleScopeArrays | boolean | true | Flag const arrays used exclusively for .includes() or membership-style indexOf() tests (Pattern C). |