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

  1. Convert the collection to `const set = new Set([...])` and replace `.includes(x)` with `set.has(x)`.
  2. 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`.
  3. If flags are pervasive and intentional (small constant arrays where the perf win is negligible), turn the rule off in `.oxlintrc.json`.
  4. 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

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


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/d300a839232b119a. Report an issue: GitHub.