oxc-project/oxc · warning · OxcDiagnostic
should be a `Set`, and use `.has()` to check existence or no
Error message
should be a `Set`, and use `.has()` to check existence or non-existence.
What it means
This is the oxlint rule `unicorn/prefer-set-has` (category `perf`, fix marked `dangerous_fix`). It fires when an array is used only for existence checks via `Array#includes()` even though a `Set` with `Set#has()` would do the same job in O(1) instead of O(n). The diagnostic is attached to the array declaration or the `.includes()` usage, telling you the value 'should be a `Set`, and use `.has()`'.
Source
Thrown at crates/oxc_linter/src/rules/unicorn/prefer_set_has.rs:35
"concat",
"copyWithin",
"fill",
"filter",
"flat",
"flatMap",
"map",
"reverse",
"slice",
"sort",
"splice",
"toReversed",
"toSorted",
"toSpliced",
"with",
];
fn prefer_set_has_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("should be a `Set`, and use `.has()` to check existence or non-existence.")
.with_help("Switch to `Set`")
.with_label(span)
}
#[derive(Debug, Default, Clone)]
pub struct PreferSetHas;
declare_oxc_lint!(
/// ### What it does
///
/// Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence.
///
/// ### Why is this bad?
///
/// `Set#has()` is faster than `Array#includes()`.
///
/// ### Examples
///View on GitHub (pinned to e1e7af627c)
Solutions
- Convert the collection to `const set = new Set([...])` and replace `.includes(x)` with `set.has(x)`.
- If the value must stay an array (iterated, indexed, deduped order matters, or used with array methods), keep `.includes()` and disable the rule for the line: `// oxlint-disable unicorn/prefer-set-has`.
- If flags are pervasive and intentional (small constant arrays where the perf win is negligible), turn the rule off in `.oxlintrc.json`.
- Apply the autofix with `oxlint --fix` only after confirming every other usage of the variable tolerates a `Set`.
Example fix
// before const allowed = ['read', 'write', 'admin']; const can = (role) => allowed.includes(role); // after const allowed = new Set(['read', 'write', 'admin']); const can = (role) => allowed.has(role);
Defensive patterns
Strategy: validation
Validate before calling
// Pre-check helper: use Set when the collection is only used for membership
function membershipCollection(values) {
return new Set(values);
}
const allowed = membershipCollection(['read', 'write']);
if (allowed.has(role)) { /* ... */ } Prevention
- Default to `Set` for constant lookup collections; only keep arrays when you iterate/index or need duplicates.
- Watch for `dangerous_fix`: after `oxlint --fix`, confirm no remaining `.map/.filter/.length` usages on the converted variable.
- Gate the rule in CI with `oxlint --deny-warn unicorn/prefer-set-has` on hot-path directories only.
When it happens
Trigger: An array built from an array literal, `new Array()`, `Array.from()`, `Array.of()`, or an array-returning method from the tracked list (map/filter/slice/concat/sort/...) whose only meaningful use is `arr.includes(value)` — typically inside a loop or a callback called repeatedly, at the same scope, without intervening mutation (checks via `is_multiple_calls` and scope analysis).
Common situations: Membership tests like `const VALID = ['a','b','c']; if (VALID.includes(x))` in hot paths, or generated code migrated from ESLint unicorn configs; also flagged in code reviews where the array is also spread/indexed elsewhere — the auto-fix is dangerous precisely because other usages may still require a real array.
Related errors
- Function `{name}` does not capture any variables from its pa
- This function does not use any variables from its parent sco
- The {expr_type} is useless
- `{description}` accepts an iterable, `.toArray()` is unneces
- `for…of` can iterate over an iterable, `.toArray()` is unnec
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/d300a839232b119a.
Report an issue: GitHub.