oxc-project/oxc · warning
Prefer a single `.flatMap(…)` over `.filter(…).flatMap(…)`.
Error message
Prefer a single `.flatMap(…)` over `.filter(…).flatMap(…)`.
What it means
This is a lint diagnostic from the oxlint rule `unicorn/prefer-array-flat-map`. It fires when code chains `.filter(...).flatMap(...)` on the same receiver, because the filter step can be inlined as an array literal returned by the flatMap callback, yielding a single `.flatMap(…)` call. The library throws it to steer developers toward simpler, more idiomatic array chaining.
Solutions
- Replace `.filter(predicate).flatMap(cb)` with a single `.flatMap(el => predicate(el) ? [...] : [])`, inlining the predicate condition into the callback.
- Apply the rule's provided auto-fix (it rewrites the chain, adding grouping parentheses around the predicate when used as a conditional test).
- Disable or downgrade `unicorn/prefer-array-flat-map` in .oxlintrc.json if the two-call form is preferred.
Example fix
// before const ids = users.filter(u => u.active).flatMap(u => [u.id, u.parentId]); // after const ids = users.flatMap(u => u.active ? [u.id, u.parentId] : []);
Defensive patterns
Strategy: validation
Validate before calling
// oxlint config check before CI
// .oxlintrc.json
// { "rules": { "unicorn/prefer-array-flat-map": "warn" } }
// pre-commit: npx oxlint --fix --rule 'unicorn/prefer-array-flat-map':error Prevention
- Write flatMap-first: inline filter predicates into the flatMap callback from the start.
- Run `oxlint --fix` locally before committing to let the rule rewrite chains automatically.
- Enable the unicorn preset in code review so the style is enforced continuously.
When it happens
Trigger: oxlint detects `x.filter(fn).flatMap(cb)` where the filter callback name matches the flatMap callback's predicate name (simple_callback on the flatMap argument), the flatMap callback returns an array literal with more than one element (so inlining is beneficial), and the receiver is not a known non-indexed object (checked via is_known_non_indexed_receiver).
Common situations: Seen in everyday data-transformation code where developers filter then flatMap over arrays; also appears in migration runs when enabling unicorn presets, and in CI when new oxlint versions add this rule.
Understand the failure class
Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.
Related errors
- Prefer `String#at()` over `String#substring()` when getting…
- A regular expression literal can be confused with '/='.
- Assign array to a variable before exporting as module…
- Avoid nesting promises.
- Avoid unnecessary use of .
AI-assisted analysis of oxc-project/oxc@12cb547351 (2026-09-20).
Data as JSON: /api/errors/59708f083d8bd3da.
Report an issue: GitHub.
Appendix: source
Thrown at crates/oxc_linter/src/rules/unicorn/prefer_array_flat_map.rs:163
&& member.property.name == "flatMap"
&& let Expression::CallExpression(filter) = member.object.get_inner_expression()
&& !filter.optional
&& filter.type_arguments.is_none()
&& filter.arguments.len() == 1
&& let Expression::StaticMemberExpression(filter_member) =
filter.callee.get_inner_expression()
&& !filter_member.optional
&& filter_member.property.name == "filter"
&& !has_optional_chain(&filter_member.object)
&& !ctx.has_comments_between(call.span)
&& let Some((filter_name, predicate)) = simple_callback(&filter.arguments[0])
&& let Some((map_name, mapped)) = simple_callback(&call.arguments[0])
&& filter_name == map_name
&& matches!(mapped.without_parentheses(), Expression::ArrayExpression(array) if array.elements.len() > 1)
&& !is_known_non_indexed_receiver(&filter_member.object, ctx)
{
ctx.diagnostic_with_suggestion(
OxcDiagnostic::warn("Prefer a single `.flatMap(…)` over `.filter(…).flatMap(…)`.")
.with_label(member.property.span),
|fixer| {
let receiver = fixer.source_range(filter_member.object.span());
let predicate_text = fixer.source_range(predicate.span());
// These expressions need grouping when used as the test of a conditional.
let predicate_text = if matches!(
predicate,
Expression::ArrowFunctionExpression(_)
| Expression::AssignmentExpression(_)
| Expression::ClassExpression(_)
| Expression::ConditionalExpression(_)
| Expression::FunctionExpression(_)
| Expression::ObjectExpression(_)
| Expression::SequenceExpression(_)
| Expression::TSAsExpression(_)
| Expression::TSNonNullExpression(_)
| Expression::TSSatisfiesExpression(_)
| Expression::TSTypeAssertion(_)View on GitHub (pinned to 12cb547351)