Skip to content

feat(linter): add noReactObjectTypeAsDefaultProp rule - #10634

Merged
ematipico merged 26 commits into
biomejs:mainfrom
subaru-hello:feat/no-object-type-as-default-prop
Sep 19, 2026
Merged

ematipico merged 26 commits into
biomejs:mainfrom
subaru-hello:feat/no-object-type-as-default-prop

Conversation

@subaru-hello

@subaru-hello subaru-hello commented Jun 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Ports no-object-type-as-default-prop from eslint-plugin-react as noObjectTypeAsDefaultProp in the nursery group.

The rule reports reference-type defaults on destructured props of React function components. These create a new instance on every render, which can break memoization and trigger extra re-renders. Primitive defaults are fine.

It flags the following default value types:

  • object literals ({})
  • array literals ([])
  • arrow functions / function expressions
  • class expressions
  • new expressions
  • JSX elements
  • regular expressions
  • Symbol() calls

Closes #7656

Notes

  • Component detection uses Biome's existing ReactComponentInfo (name + param count), not return-value analysis. Two cases differ from upstream:
    • export default function NotReturningJsx({ foo = {} }) {} is reported (PascalCase name).
    • ({ a = {} }, context) => {} is not reported (two params, so not a component here).
  • Handles function declarations, arrow/function expressions in a PascalCase variable, memo/forwardRef wrappers, and default-exported functions.
  • Checks top-level defaults, including aliased properties, like upstream.

Test plan

  • cargo test -p biome_js_analyze -- no_object_type_as_default_prop
  • cargo run -p rules_check
  • just gen-analyzer

The committed snapshots (invalid.jsx.snap / valid.jsx.snap) show the rendered diagnostics for every flagged type.

AI usage disclosure

I used an AI assistant (Claude) heavily while writing this PR — for finding the right syntax-tree APIs, writing a lot of the traversal code, fixing compile errors, and polishing the docs. I made the design decisions (how components are detected, which default types to flag, the differences from upstream), wrote the test cases, and reviewed and verified all the code.

@changeset-bot

changeset-bot Bot commented Jun 14, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d3a0e0e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-win32-x64 Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/wasm-web Patch
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

Copy link
Copy Markdown
Contributor

✅ Organic activity

No automation signals detected in the analyzed events.

View full analysis →

This is an automated analysis by AgentScan

@github-actions github-actions Bot added A-CLI Area: CLI A-Project Area: project A-Linter Area: linter L-JavaScript Language: JavaScript and super languages A-Diagnostic Area: diagnostocis labels Jun 14, 2026
@coderabbitai

coderabbitai Bot commented Jun 14, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The PR implements the noReactObjectTypeAsDefaultProp lint rule to detect non-primitive default values assigned to destructured React component props. The rule identifies forbidden kinds—object literals, array literals, arrow functions, functions, class expressions, new expressions, JSX elements, regex literals, and Symbol(...) calls—extracts them from component parameter binding patterns, and reports diagnostics explaining that React treats each as a different value on every render. The rule is registered in the options module and documented via changeset entry.

Suggested reviewers

  • dyc3
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR successfully implements the requested rule from issue #7656, using the suggested name noObjectTypeAsDefaultProp and covering all flagged default value types.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the noObjectTypeAsDefaultProp rule. The three modified files (module export, changeset, and rule implementation) are all necessary and in-scope.
Title check ✅ Passed The title accurately describes the main change: adding the noReactObjectTypeAsDefaultProp linter rule to Biome.
Description check ✅ Passed The pull request description directly describes the new noObjectTypeAsDefaultProp rule, its flagged value types, implementation scope, behavioural differences, and test plan. It matches the changeset.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.changeset/add-no-object-type-as-default-prop.md (1)

5-5: ⚡ Quick win

Add a tiny invalid example.

As per coding guidelines, new lint-rule changesets should show an invalid case, not just prose. A single inline example would make this easier to scan.

💡 Suggested tweak
-Added [`noObjectTypeAsDefaultProp`](https://biomejs.dev/linter/rules/no-object-type-as-default-prop/) to the nursery group. This rule disallows reference-type values (arrays, objects, functions, classes, `new` expressions, JSX elements, regular expressions, and `Symbol()`) as default values for destructured props in React function components, because a new instance is created on every render, which can break memoization and cause unnecessary re-renders. It ports [`no-object-type-as-default-prop`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-object-type-as-default-prop.md) from `eslint-plugin-react`.
+Added [`noObjectTypeAsDefaultProp`](https://biomejs.dev/linter/rules/no-object-type-as-default-prop/) to the nursery group. For example, `function Foo({ bar = {} }) {}` is now flagged. This rule disallows reference-type values (arrays, objects, functions, classes, `new` expressions, JSX elements, regular expressions, and `Symbol()`) as default values for destructured props in React function components, because a new instance is created on every render, which can break memoization and cause unnecessary re-renders. It ports [`no-object-type-as-default-prop`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-object-type-as-default-prop.md) from `eslint-plugin-react`.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/add-no-object-type-as-default-prop.md at line 5, The changeset
file for the noObjectTypeAsDefaultProp rule lacks an invalid code example, which
is required per coding guidelines for lint-rule changesets. Add a single inline
code example after the prose description that demonstrates invalid usage of the
rule, such as a React function component with a destructured prop that has a
reference-type default value (like an object literal, array, or function). This
will make the changeset easier to scan and understand what the rule disallows.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/biome_rule_options/src/no_object_type_as_default_prop.rs`:
- Line 6: The public struct NoObjectTypeAsDefaultPropOptions is missing rustdoc
documentation. Add a rustdoc comment (using ///) above the struct definition
that briefly describes the purpose of this options type container. Even though
the struct is currently empty, the doc comment should explain what configuration
options it will hold or what the rule option is for, to comply with the
repository's documentation requirements for public types.

---

Nitpick comments:
In @.changeset/add-no-object-type-as-default-prop.md:
- Line 5: The changeset file for the noObjectTypeAsDefaultProp rule lacks an
invalid code example, which is required per coding guidelines for lint-rule
changesets. Add a single inline code example after the prose description that
demonstrates invalid usage of the rule, such as a React function component with
a destructured prop that has a reference-type default value (like an object
literal, array, or function). This will make the changeset easier to scan and
understand what the rule disallows.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f616111a-5e29-48cd-bda9-71c23b563051

📥 Commits

Reviewing files that changed from the base of the PR and between 5f837df and 8a3ada2.

⛔ Files ignored due to path filters (7)
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/linter_options_check.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noObjectTypeAsDefaultProp/invalid.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noObjectTypeAsDefaultProp/valid.jsx.snap is excluded by !**/*.snap and included by **
  • packages/@biomejs/backend-jsonrpc/src/workspace.ts is excluded by !**/backend-jsonrpc/src/workspace.ts and included by **
  • packages/@biomejs/biome/configuration_schema.json is excluded by !**/configuration_schema.json and included by **
📒 Files selected for processing (7)
  • .changeset/add-no-object-type-as-default-prop.md
  • crates/biome_cli/Cargo.toml
  • crates/biome_js_analyze/src/lint/nursery/no_object_type_as_default_prop.rs
  • crates/biome_js_analyze/tests/specs/nursery/noObjectTypeAsDefaultProp/invalid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noObjectTypeAsDefaultProp/valid.jsx
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/no_object_type_as_default_prop.rs

Comment thread crates/biome_rule_options/src/no_object_type_as_default_prop.rs Outdated
@subaru-hello
subaru-hello changed the base branch from main to next June 14, 2026 09:53
@subaru-hello
subaru-hello marked this pull request as draft June 14, 2026 09:53
@subaru-hello
subaru-hello force-pushed the feat/no-object-type-as-default-prop branch 2 times, most recently from 7b259b2 to ab86779 Compare June 14, 2026 10:23
@subaru-hello
subaru-hello marked this pull request as ready for review June 14, 2026 10:25
@subaru-hello
subaru-hello force-pushed the feat/no-object-type-as-default-prop branch from 1597b45 to b0382d3 Compare June 14, 2026 10:29

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/add-no-object-type-as-default-prop.md:
- Line 5: The changeset description in the
`.changeset/add-no-object-type-as-default-prop.md` file is missing a full stop
at the end of the sentence. Add a period at the end of the description text that
starts with "Added [`noObjectTypeAsDefaultProp`]..." to comply with the coding
guideline that every sentence must end with a full stop.

In `@crates/biome_js_analyze/src/lint/nursery/no_object_type_as_default_prop.rs`:
- Around line 211-233: The `.ok()?` calls at the property extraction (after
iterating in the for loop) and at the initializer expression unwrapping are
causing early returns from the entire function when encountering parse errors,
which prevents checking remaining properties and loses any violations already
found. Replace the `.ok()?` at line 212 (after `let property = property`) with a
`let Some(...) else { continue; }` pattern to skip malformed properties, and
similarly replace the `.ok()?` at line 223 (at `initializer.expression().ok()?`)
with the same pattern to skip missing or invalid initializer expressions. This
keeps the function iterating through all properties and collects all violations
without early termination.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9320c104-b812-4597-8632-44b64d65667e

📥 Commits

Reviewing files that changed from the base of the PR and between 8a3ada2 and ab86779.

⛔ Files ignored due to path filters (7)
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/linter_options_check.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noObjectTypeAsDefaultProp/invalid.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noObjectTypeAsDefaultProp/valid.jsx.snap is excluded by !**/*.snap and included by **
  • packages/@biomejs/backend-jsonrpc/src/workspace.ts is excluded by !**/backend-jsonrpc/src/workspace.ts and included by **
  • packages/@biomejs/biome/configuration_schema.json is excluded by !**/configuration_schema.json and included by **
📒 Files selected for processing (7)
  • .changeset/add-no-object-type-as-default-prop.md
  • crates/biome_cli/Cargo.toml
  • crates/biome_js_analyze/src/lint/nursery/no_object_type_as_default_prop.rs
  • crates/biome_js_analyze/tests/specs/nursery/noObjectTypeAsDefaultProp/invalid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noObjectTypeAsDefaultProp/valid.jsx
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/no_object_type_as_default_prop.rs
✅ Files skipped from review due to trivial changes (2)
  • crates/biome_cli/Cargo.toml
  • crates/biome_rule_options/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • crates/biome_rule_options/src/no_object_type_as_default_prop.rs
  • crates/biome_js_analyze/tests/specs/nursery/noObjectTypeAsDefaultProp/valid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noObjectTypeAsDefaultProp/invalid.jsx

"@biomejs/biome": patch
---

Added [`noObjectTypeAsDefaultProp`](https://biomejs.dev/linter/rules/no-object-type-as-default-prop/) to the nursery group. This rule disallows reference-type values (arrays, objects, functions, classes, `new` expressions, JSX elements, regular expressions, and `Symbol()`) as default values for destructured props in React function components, because a new instance is created on every render, which can break memoization and cause unnecessary re-renders. It ports [`no-object-type-as-default-prop`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-object-type-as-default-prop.md) from `eslint-plugin-react`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a full stop at the end.

As per coding guidelines, every sentence in a changeset must end with a full stop.

📝 Proposed fix
-Added [`noObjectTypeAsDefaultProp`](https://biomejs.dev/linter/rules/no-object-type-as-default-prop/) to the nursery group. This rule disallows reference-type values (arrays, objects, functions, classes, `new` expressions, JSX elements, regular expressions, and `Symbol()`) as default values for destructured props in React function components, because a new instance is created on every render, which can break memoization and cause unnecessary re-renders. It ports [`no-object-type-as-default-prop`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-object-type-as-default-prop.md) from `eslint-plugin-react`
+Added [`noObjectTypeAsDefaultProp`](https://biomejs.dev/linter/rules/no-object-type-as-default-prop/) to the nursery group. This rule disallows reference-type values (arrays, objects, functions, classes, `new` expressions, JSX elements, regular expressions, and `Symbol()`) as default values for destructured props in React function components, because a new instance is created on every render, which can break memoization and cause unnecessary re-renders. It ports [`no-object-type-as-default-prop`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-object-type-as-default-prop.md) from `eslint-plugin-react`.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Added [`noObjectTypeAsDefaultProp`](https://biomejs.dev/linter/rules/no-object-type-as-default-prop/) to the nursery group. This rule disallows reference-type values (arrays, objects, functions, classes, `new` expressions, JSX elements, regular expressions, and `Symbol()`) as default values for destructured props in React function components, because a new instance is created on every render, which can break memoization and cause unnecessary re-renders. It ports [`no-object-type-as-default-prop`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-object-type-as-default-prop.md) from `eslint-plugin-react`.
Added [`noObjectTypeAsDefaultProp`](https://biomejs.dev/linter/rules/no-object-type-as-default-prop/) to the nursery group. This rule disallows reference-type values (arrays, objects, functions, classes, `new` expressions, JSX elements, regular expressions, and `Symbol()`) as default values for destructured props in React function components, because a new instance is created on every render, which can break memoization and cause unnecessary re-renders. It ports [`no-object-type-as-default-prop`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-object-type-as-default-prop.md) from `eslint-plugin-react`.
🧰 Tools
🪛 LanguageTool

[formatting] ~5-~5: If the ‘because’ clause is essential to the meaning, do not use a comma before the clause.
Context: ...tured props in React function components, because a new instance is created on every rend...

(COMMA_BEFORE_BECAUSE)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/add-no-object-type-as-default-prop.md at line 5, The changeset
description in the `.changeset/add-no-object-type-as-default-prop.md` file is
missing a full stop at the end of the sentence. Add a period at the end of the
description text that starts with "Added [`noObjectTypeAsDefaultProp`]..." to
comply with the coding guideline that every sentence must end with a full stop.

Source: Coding guidelines

Comment thread crates/biome_js_analyze/src/lint/nursery/no_react_object_type_as_default_prop.rs Outdated
@ematipico ematipico added the M-Likely Agent Meta: this was likely an automated PR without a human in the loop label Jun 14, 2026

@ematipico ematipico left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new rule, it goes to main

///
pub NoObjectTypeAsDefaultProp {
version: "next",
name: "noObjectTypeAsDefaultProp",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it's a react focused rule, we should name this "noReact..."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense, and I fixed it.

Comment thread crates/biome_js_analyze/src/lint/nursery/no_object_type_as_default_prop.rs Outdated

@ematipico ematipico left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass of review.

use crate::react::components::{AnyPotentialReactComponentDeclaration, ReactComponentInfo};

declare_lint_rule! {
/// Disallow reference-type values as default values for destructured props.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use beginner friendly language. What's reference-type?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By "reference type" I meant arrays, objects, and functions (values compared by identity), not by value ([] !== []).
I've dropped the term and rewritten the docs in plain language.

Comment on lines +17 to +25
/// Arrays, objects, and functions are compared by reference, not by value.
/// A default value like `{ items = [] }` runs on every render, so `items` is a
/// new array every time. React compares by reference, so it thinks the value
/// changed. This breaks memoization (such as `React.memo`, `useMemo`, or
/// `useEffect` dependency arrays) and causes extra re-renders. Primitives are
/// safe because they are compared by value.
///
/// To fix a violation, declare the value as a constant outside the component
/// and use it as the default.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs are very, very technical since the beginning and they don't explain very well what this rule is for. Please use a beginning friendly language.

Also the "to fix a violation" part is redundant, it should be explained in the diagnostic of the rule

Comment on lines +73 to +75
let Some(_component) = ReactComponentInfo::from_declaration(node.syntax()) else {
return vec![];
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use is_some

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried is_some() first, but it read worse for an early return (it becomes !is_some(), which clippy also flags), so I went with is_none(). Let me know if you'd prefer otherwise.

@ematipico ematipico Jun 14, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah what clippy says. It's basically pointless having a let-else with a binding you don't use

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, the is_none() version drops the binding entirely, which was the real issue. Thanks!

Comment on lines +89 to +97
"Avoid using "{kind}" as the default value of a destructured prop."
},
)
.note(markup! {
"Reference-type defaults create a new value on every render, which can break memoization and may cause unnecessary re-renders or, in some cases, infinite render loops."
})
.note(markup! {
"Use a constant defined outside the component as the default value instead."
}),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diagnostics don't follow the rule pillars https://biomejs.dev/linter/#rule-pillars

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you.
Reworked the diagnostic to follow the three pillars (what's wrong (message), why (note), and how to fix (note))

@subaru-hello
subaru-hello changed the base branch from next to main June 14, 2026 11:11
@subaru-hello
subaru-hello force-pushed the feat/no-object-type-as-default-prop branch from b0382d3 to b189e6c Compare June 14, 2026 12:32
@subaru-hello
subaru-hello requested review from dyc3 and ematipico June 14, 2026 12:45
name: "noReactObjectTypeAsDefaultProp",
language: "js",
sources: &[RuleSource::EslintReact("no-object-type-as-default-prop").same()],
recommended: false,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make this recommended? The source rule currently isn't, but however I found jsx-eslint/eslint-plugin-react#3863

What do you think?

@subaru-hello subaru-hello Jun 14, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good point. I'm in favor.
This is an easy mistake to make, and recommending it would help beginners especially. jsx-eslint/eslint-plugin-react#3863 shows the same demand upstream.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I go ahead and set it to recommended?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, let's do it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, it's recommended now 43b7a7b

@subaru-hello
subaru-hello requested a review from dyc3 June 14, 2026 23:09

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
crates/biome_js_analyze/src/lint/nursery/no_react_object_type_as_default_prop.rs (1)

213-235: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Early return discards violations and skips remaining properties.

Lines 214 and 225 use .ok()? inside the for loop, causing the entire function to return None when any property or initialiser expression fails to parse. This discards any violations already collected in defaults and prevents checking the remaining properties.

Replace .ok()? with let Ok(...) else { continue } to skip malformed entries whilst continuing to accumulate violations.

🔧 Proposed fix
 let mut defaults = Vec::new();
 for property in object_pattern.properties() {
-    let property = property.ok()?;
+    let Ok(property) = property else {
+        continue;
+    };

     let AnyJsObjectBindingPatternMember::JsObjectBindingPatternShorthandProperty(shorthand) =
         property
     else {
         continue;
     };

     let Some(initializer) = shorthand.init() else {
         continue;
     };
-    let default_value = initializer.expression().ok()?;
+    let Ok(default_value) = initializer.expression() else {
+        continue;
+    };

     let Some(kind) = forbidden_default_kind(&default_value) else {
         continue;
     };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@crates/biome_js_analyze/src/lint/nursery/no_react_object_type_as_default_prop.rs`
around lines 213 - 235, In the for loop that iterates through
object_pattern.properties(), replace the two `.ok()?` calls with the `let
Ok(...) else { continue }` pattern. Specifically, change the line that assigns
property from property.ok()? to use let Ok(property) = property else { continue
}, and change the line that assigns default_value from
initializer.expression().ok()? to use let Ok(default_value) =
initializer.expression() else { continue }. This prevents early function return
on parse errors and allows the loop to continue accumulating violations in the
defaults vector while skipping malformed entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In
`@crates/biome_js_analyze/src/lint/nursery/no_react_object_type_as_default_prop.rs`:
- Around line 213-235: In the for loop that iterates through
object_pattern.properties(), replace the two `.ok()?` calls with the `let
Ok(...) else { continue }` pattern. Specifically, change the line that assigns
property from property.ok()? to use let Ok(property) = property else { continue
}, and change the line that assigns default_value from
initializer.expression().ok()? to use let Ok(default_value) =
initializer.expression() else { continue }. This prevents early function return
on parse errors and allows the loop to continue accumulating violations in the
defaults vector while skipping malformed entries.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 23ad1c4d-e2a7-4ea2-ba5c-df362fa50476

📥 Commits

Reviewing files that changed from the base of the PR and between b189e6c and 43b7a7b.

📒 Files selected for processing (1)
  • crates/biome_js_analyze/src/lint/nursery/no_react_object_type_as_default_prop.rs

"@biomejs/biome": patch
---

Added the new nursery rule [`noReactObjectTypeAsDefaultProp`](https://biomejs.dev/linter/rules/no-react-object-type-as-default-prop/).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use a little more info on what the rule is about (+ perhaps an example of an invalid case)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For nursery rules we usually keep the changeset a one-liner, right? (per this thread)
#10634 (comment)

@Netail Netail Jun 17, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think he means that it should start that way (to stay consistent with all new rule changesets). After that you can include a short summary of what the rule does

E.g. https://github.com/biomejs/biome/pull/10498/changes#diff-b730f12cf2b925551bdabe6447c2c27b33a81cd6a366e05b5043e39c8cc42eee

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, I misunderstood. one-liner first, then a short summary. Fixing it now, thanks!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it. 40be90e

@subaru-hello
subaru-hello requested a review from Netail June 17, 2026 10:07
@codspeed

codspeed Bot commented Jun 17, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 74 untouched benchmarks
⏩ 284 skipped benchmarks1


Comparing subaru-hello:feat/no-object-type-as-default-prop (d3a0e0e) with main (807f81a)2

Open in CodSpeed

Footnotes

  1. 284 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

  2. No successful run was found on main (2b5cd1e) during the generation of this report, so 807f81a was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

…-as-default-prop

# Conflicts:
#	crates/biome_diagnostics_categories/src/categories.rs
#	packages/@biomejs/backend-jsonrpc/src/workspace.ts
@subaru-hello

Copy link
Copy Markdown
Contributor Author

@ematipico
Merged main and resolved the conflicts.
PTAL when you have a moment, thanks!

@subaru-hello

Copy link
Copy Markdown
Contributor Author

@ematipico

Hi!
I've resolved the conflicts with main. Could you please approve the workflow runs?

@ematipico ematipico left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

almost there

use crate::react::components::{AnyPotentialReactComponentDeclaration, ReactComponentInfo};

declare_lint_rule! {
/// Disallow array, object, and function values as default props.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Disallow array, object, and function values as default props.
/// Disallow array, object, and function values as default props in React components.

Comment on lines +23 to +24
/// Numbers, strings, and other primitives are fine, because they stay the same
/// between renders.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Numbers, strings, and other primitives are fine, because they stay the same
/// between renders.
/// Numbers, strings, and other primitives are fine, because they stay the same
/// among renders.

Use "Between" when you have exactly two parties. For three or more, you use among

kind: ForbiddenDefaultKind,
}

fn forbidden_default_kind(expression: &AnyJsExpression) -> Option<ForbiddenDefaultKind> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's idiomatic doing

impl ForbiddenDefaultKind {
	fn from_expression(expr: &AnyJsExpression) -> Option<Self> {}
}

}
}

fn function_parameters(function: &AnyJsFunction) -> Option<JsParameters> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shoudl add this function here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ematipico
Moved it to function_ext.rs in 377f13b.
Could you take another look?

@github-actions github-actions Bot added the A-Parser Area: parser label Sep 18, 2026
@ematipico

Copy link
Copy Markdown
Member

@biome-cookie review

@biome-cookie biome-cookie left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

Review complete. 1 finding was added inline.

Questions

  • The rule uses severity: Severity::Error, while the similar nursery React rule noReactStringRefs uses Severity::Warning. Was Error chosen intentionally here?

  • Is limiting checks to top-level shorthand destructuring a deliberate departure from eslint-plugin-react/no-object-type-as-default-prop, or should aliased and nested defaults also be reported?

Review Status

  • Scope: 2b5cd1e...2ca4c3a

  • Branch target: main

  • Changeset: add-no-react-object-type-as-default-prop.md

  • Brief: Reviewed; no blocking issues identified.

  • Validation: Static review only; no project code was run.

  • Fetch: git fetch origin 2ca4c3a

object_pattern
.properties()
.into_iter()
.filter_map(|property| {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional/completeness: Only shorthand destructuring defaults are checked

collect_forbidden_defaults intentionally narrows the rule to JsObjectBindingPatternShorthandProperty. This means aliased defaults (e.g. { a: b = {} }) and nested defaults are skipped. If this is a deliberate departure from upstream, consider adding an explicit valid test case such as function C({ a: b = {} }) {} to lock the behaviour and make the scope unambiguous to future maintainers.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@subaru-hello, the bot found something that should be addressed. If intentional, it needs to be documented. If not, cover it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not intentional, so I’ll fix it and add a test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ematipico

Fixed in d3a0e0e and added regression tests !

@ematipico
ematipico merged commit b436ba0 into biomejs:main Sep 19, 2026
37 checks passed
@github-actions github-actions Bot mentioned this pull request Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CLI Area: CLI A-Diagnostic Area: diagnostocis A-Linter Area: linter A-Parser Area: parser A-Project Area: project L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

📎 Port no-object-type-as-default-prop from react rules

5 participants