Repository: biomejs/biome (language: rust)

Issue:
📎 Implement `noUselessUndefined` - `unicorn/no-useless-undefined`
### Description

Implement [no-useless-undefined](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-undefined.md).

**Want to contribute?** Lets you know you are interested! We will assign you to the issue to prevent several people to work on the same issue. Don't worry, we can unassign you later if you are no longer interested in the issue! Read our [contributing guide](https://github.com/biomejs/biome/blob/main/CONTRIBUTING.md) and [analyzer contributing guide](https://github.com/biomejs/biome/blob/main/crates/biome_analyze/CONTRIBUTING.md).

The implementer could take some inspirations from the implementation of existing rules such as `noUselessUndefinedInitialization`.


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b9cebcfd8066..0a18239f5b17 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,27 @@ New entries must be placed in a section entitled `Unreleased`.
 Read
 our [guidelines for writing a good changelog entry](https://github.com/biomejs/biome/blob/main/CONTRIBUTING.md#changelog).
 
+## Unreleased
+
+### Analyzer
+
+### CLI
+
+### Configuration
+
+### Editors
+
+### Formatter
+
+### JavaScript APIs
+
+### Linter
+
+#### New features
+
+- Add [noUselessUndefined](https://biomejs.dev/linter/rules/no-useless-undefined/). Contributed by @unvalley
+
+
 ## v1.9.4 (2024-10-17)
 
 ### Analyzer
@@ -189,6 +210,30 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b
 
 ### Parser
 
+<<<<<<< HEAD
+#### New features
+
+- Add support for parsing the defer attribute in import statements ([#4215](https://github.com/biomejs/biome/issues/4215)).
+
+   ```js
+   import defer * as myModule from "my-module";
+   ```
+
+  Contributed by @fireairforce
+
+||||||| ea7d35c26a
+#### New features
+
+- Add support for parsing the defer attribute in import statements ([#4215](https://github.com/biomejs/biome/issues/4215)).
+
+   ```js
+   import defer * as myModule from "my-module";
+   ```
+
+  Contributed by @fireairforce
+
+=======
+>>>>>>> main
 #### Bug Fixes
 
 - The CSS parser now accepts more emoji in identifiers ([#3627](https://github.com/biomejs/biome/issues/3627#issuecomment-2392388022)).
diff --git a/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs b/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs
index 0a8e2f2a7ec0..86772b4df63f 100644
--- a/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs
+++ b/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs
@@ -1578,6 +1578,14 @@ pub(crate) fn migrate_eslint_any_rule(
                 .get_or_insert(Default::default());
             rule.set_level(rule_severity.into());
         }
+        "unicorn/no-useless-undefined" => {
+            if !options.include_nursery {
+                return false;
+            }
+            let group = rules.nursery.get_or_insert_with(Default::default);
+            let rule = group.no_useless_undefined.get_or_insert(Default::default());
+            rule.set_level(rule_severity.into());
+        }
         "unicorn/prefer-array-flat-map" => {
             let group = rules.complexity.get_or_insert_with(Default::default);
             let rule = group.use_flat_map.get_or_insert(Default::default());
diff --git a/crates/biome_configuration/src/analyzer/linter/rules.rs b/crates/biome_configuration/src/analyzer/linter/rules.rs
index 2bfe89e761e4..8f6f8d302ff0 100644
--- a/crates/biome_configuration/src/analyzer/linter/rules.rs
+++ b/crates/biome_configuration/src/analyzer/linter/rules.rs
@@ -3381,6 +3381,10 @@ pub struct Nursery {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub no_useless_string_raw:
         Option<RuleConfiguration<biome_js_analyze::options::NoUselessStringRaw>>,
+    #[doc = "Disallow the use of useless undefined."]
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub no_useless_undefined:
+        Option<RuleFixConfiguration<biome_js_analyze::options::NoUselessUndefined>>,
     #[doc = "Disallow use of @value rule in css modules."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub no_value_at_rule: Option<RuleConfiguration<biome_css_analyze::options::NoValueAtRule>>,
@@ -3491,6 +3495,7 @@ impl Nursery {
         "noUnknownTypeSelector",
         "noUselessEscapeInRegex",
         "noUselessStringRaw",
+        "noUselessUndefined",
         "noValueAtRule",
         "useAdjacentOverloadSignatures",
         "useAriaPropsSupportedByRole",
@@ -3536,10 +3541,10 @@ impl Nursery {
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45]),
     ];
     const ALL_RULES_AS_FILTERS: &'static [RuleFilter<'static>] = &[
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[0]),
@@ -3589,6 +3594,7 @@ impl Nursery {
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47]),
     ];
     #[doc = r" Retrieves the recommended rules"]
     pub(crate) fn is_recommended_true(&self) -> bool {
@@ -3755,91 +3761,96 @@ impl Nursery {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29]));
             }
         }
-        if let Some(rule) = self.no_value_at_rule.as_ref() {
+        if let Some(rule) = self.no_useless_undefined.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30]));
             }
         }
-        if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() {
+        if let Some(rule) = self.no_value_at_rule.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31]));
             }
         }
-        if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() {
+        if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32]));
             }
         }
-        if let Some(rule) = self.use_at_index.as_ref() {
+        if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33]));
             }
         }
-        if let Some(rule) = self.use_collapsed_if.as_ref() {
+        if let Some(rule) = self.use_at_index.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34]));
             }
         }
-        if let Some(rule) = self.use_component_export_only_modules.as_ref() {
+        if let Some(rule) = self.use_collapsed_if.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35]));
             }
         }
-        if let Some(rule) = self.use_consistent_curly_braces.as_ref() {
+        if let Some(rule) = self.use_component_export_only_modules.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36]));
             }
         }
-        if let Some(rule) = self.use_consistent_member_accessibility.as_ref() {
+        if let Some(rule) = self.use_consistent_curly_braces.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37]));
             }
         }
-        if let Some(rule) = self.use_deprecated_reason.as_ref() {
+        if let Some(rule) = self.use_consistent_member_accessibility.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38]));
             }
         }
-        if let Some(rule) = self.use_explicit_type.as_ref() {
+        if let Some(rule) = self.use_deprecated_reason.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39]));
             }
         }
-        if let Some(rule) = self.use_google_font_display.as_ref() {
+        if let Some(rule) = self.use_explicit_type.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40]));
             }
         }
-        if let Some(rule) = self.use_guard_for_in.as_ref() {
+        if let Some(rule) = self.use_google_font_display.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41]));
             }
         }
-        if let Some(rule) = self.use_import_restrictions.as_ref() {
+        if let Some(rule) = self.use_guard_for_in.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42]));
             }
         }
-        if let Some(rule) = self.use_sorted_classes.as_ref() {
+        if let Some(rule) = self.use_import_restrictions.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43]));
             }
         }
-        if let Some(rule) = self.use_strict_mode.as_ref() {
+        if let Some(rule) = self.use_sorted_classes.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44]));
             }
         }
-        if let Some(rule) = self.use_trim_start_end.as_ref() {
+        if let Some(rule) = self.use_strict_mode.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45]));
             }
         }
-        if let Some(rule) = self.use_valid_autocomplete.as_ref() {
+        if let Some(rule) = self.use_trim_start_end.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46]));
             }
         }
+        if let Some(rule) = self.use_valid_autocomplete.as_ref() {
+            if rule.is_enabled() {
+                index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47]));
+            }
+        }
         index_set
     }
     pub(crate) fn get_disabled_rules(&self) -> FxHashSet<RuleFilter<'static>> {
@@ -3994,91 +4005,96 @@ impl Nursery {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29]));
             }
         }
-        if let Some(rule) = self.no_value_at_rule.as_ref() {
+        if let Some(rule) = self.no_useless_undefined.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30]));
             }
         }
-        if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() {
+        if let Some(rule) = self.no_value_at_rule.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31]));
             }
         }
-        if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() {
+        if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32]));
             }
         }
-        if let Some(rule) = self.use_at_index.as_ref() {
+        if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33]));
             }
         }
-        if let Some(rule) = self.use_collapsed_if.as_ref() {
+        if let Some(rule) = self.use_at_index.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34]));
             }
         }
-        if let Some(rule) = self.use_component_export_only_modules.as_ref() {
+        if let Some(rule) = self.use_collapsed_if.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35]));
             }
         }
-        if let Some(rule) = self.use_consistent_curly_braces.as_ref() {
+        if let Some(rule) = self.use_component_export_only_modules.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36]));
             }
         }
-        if let Some(rule) = self.use_consistent_member_accessibility.as_ref() {
+        if let Some(rule) = self.use_consistent_curly_braces.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37]));
             }
         }
-        if let Some(rule) = self.use_deprecated_reason.as_ref() {
+        if let Some(rule) = self.use_consistent_member_accessibility.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38]));
             }
         }
-        if let Some(rule) = self.use_explicit_type.as_ref() {
+        if let Some(rule) = self.use_deprecated_reason.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39]));
             }
         }
-        if let Some(rule) = self.use_google_font_display.as_ref() {
+        if let Some(rule) = self.use_explicit_type.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40]));
             }
         }
-        if let Some(rule) = self.use_guard_for_in.as_ref() {
+        if let Some(rule) = self.use_google_font_display.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41]));
             }
         }
-        if let Some(rule) = self.use_import_restrictions.as_ref() {
+        if let Some(rule) = self.use_guard_for_in.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42]));
             }
         }
-        if let Some(rule) = self.use_sorted_classes.as_ref() {
+        if let Some(rule) = self.use_import_restrictions.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43]));
             }
         }
-        if let Some(rule) = self.use_strict_mode.as_ref() {
+        if let Some(rule) = self.use_sorted_classes.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44]));
             }
         }
-        if let Some(rule) = self.use_trim_start_end.as_ref() {
+        if let Some(rule) = self.use_strict_mode.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45]));
             }
         }
-        if let Some(rule) = self.use_valid_autocomplete.as_ref() {
+        if let Some(rule) = self.use_trim_start_end.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46]));
             }
         }
+        if let Some(rule) = self.use_valid_autocomplete.as_ref() {
+            if rule.is_disabled() {
+                index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47]));
+            }
+        }
         index_set
     }
     #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"]
@@ -4235,6 +4251,10 @@ impl Nursery {
                 .no_useless_string_raw
                 .as_ref()
                 .map(|conf| (conf.level(), conf.get_options())),
+            "noUselessUndefined" => self
+                .no_useless_undefined
+                .as_ref()
+                .map(|conf| (conf.level(), conf.get_options())),
             "noValueAtRule" => self
                 .no_value_at_rule
                 .as_ref()
diff --git a/crates/biome_diagnostics_categories/src/categories.rs b/crates/biome_diagnostics_categories/src/categories.rs
index 44caa650241c..c5b9fa49e2d5 100644
--- a/crates/biome_diagnostics_categories/src/categories.rs
+++ b/crates/biome_diagnostics_categories/src/categories.rs
@@ -183,6 +183,7 @@ define_categories! {
     "lint/nursery/noUnusedFunctionParameters": "https://biomejs.dev/linter/rules/no-unused-function-parameters",
     "lint/nursery/noUselessEscapeInRegex": "https://biomejs.dev/linter/rules/no-useless-escape-in-regex",
     "lint/nursery/noUselessStringRaw": "https://biomejs.dev/linter/rules/no-useless-string-raw",
+    "lint/nursery/noUselessUndefined": "https://biomejs.dev/linter/rules/no-useless-undefined",
     "lint/nursery/noValueAtRule": "https://biomejs.dev/linter/rules/no-value-at-rule",
     "lint/nursery/useAdjacentOverloadSignatures": "https://biomejs.dev/linter/rules/use-adjacent-overload-signatures",
     "lint/nursery/useAriaPropsSupportedByRole": "https://biomejs.dev/linter/rules/use-aria-props-supported-by-role",
diff --git a/crates/biome_js_analyze/src/lint/nursery.rs b/crates/biome_js_analyze/src/lint/nursery.rs
index d75078d2e484..61c1d46a5b78 100644
--- a/crates/biome_js_analyze/src/lint/nursery.rs
+++ b/crates/biome_js_analyze/src/lint/nursery.rs
@@ -24,6 +24,7 @@ pub mod no_substr;
 pub mod no_template_curly_in_string;
 pub mod no_useless_escape_in_regex;
 pub mod no_useless_string_raw;
+pub mod no_useless_undefined;
 pub mod use_adjacent_overload_signatures;
 pub mod use_aria_props_supported_by_role;
 pub mod use_at_index;
@@ -66,6 +67,7 @@ declare_lint_group! {
             self :: no_template_curly_in_string :: NoTemplateCurlyInString ,
             self :: no_useless_escape_in_regex :: NoUselessEscapeInRegex ,
             self :: no_useless_string_raw :: NoUselessStringRaw ,
+            self :: no_useless_undefined :: NoUselessUndefined ,
             self :: use_adjacent_overload_signatures :: UseAdjacentOverloadSignatures ,
             self :: use_aria_props_supported_by_role :: UseAriaPropsSupportedByRole ,
             self :: use_at_index :: UseAtIndex ,
diff --git a/crates/biome_js_analyze/src/lint/nursery/no_useless_undefined.rs b/crates/biome_js_analyze/src/lint/nursery/no_useless_undefined.rs
new file mode 100644
index 000000000000..9c4c01d58f1f
--- /dev/null
+++ b/crates/biome_js_analyze/src/lint/nursery/no_useless_undefined.rs
@@ -0,0 +1,307 @@
+use biome_analyze::{
+    context::RuleContext, declare_lint_rule, ActionCategory, Ast, FixKind, Rule, RuleDiagnostic,
+    RuleSource,
+};
+use biome_console::markup;
+use biome_js_factory::make::{self, js_function_body};
+use biome_js_syntax::{
+    AnyJsExpression, AnyJsFunctionBody, JsArrayBindingPatternElement, JsArrowFunctionExpression,
+    JsFormalParameter, JsObjectBindingPatternShorthandProperty, JsReturnStatement,
+    JsVariableStatement, JsYieldArgument, T,
+};
+use biome_rowan::{declare_node_union, AstNode, BatchMutationExt, TextRange, TokenText};
+
+use crate::JsRuleAction;
+
+declare_lint_rule! {
+    /// Disallow the use of useless `undefined`.
+    ///
+    /// `undefined` is the default value for new variables, parameters, return statements, etc., so specifying it doesn't make any difference.
+    ///
+    /// ## Examples
+    ///
+    /// ### Invalid
+    ///
+    /// ```js,expect_diagnostic
+    /// let foo = undefined;
+    /// ```
+    ///
+    /// ```js,expect_diagnostic
+    /// const {foo = undefined} = bar;
+    /// ```
+    ///
+    /// ```js,expect_diagnostic
+    /// const noop = () => undefined;
+    /// ```
+    ///
+    /// ```js,expect_diagnostic
+    /// function foo() {
+    ///    return undefined;
+    /// }
+    /// ```
+    ///
+    /// ```js,expect_diagnostic
+    /// function* foo() {
+    ///   yield undefined;
+    /// }
+    /// ```
+    ///
+    /// ```js,expect_diagnostic
+    /// function foo(bar = undefined) {}
+    /// ```
+    ///
+    /// ```js,expect_diagnostic
+    /// function foo({bar = undefined}) {}
+    /// ```
+    ///
+    /// ### Valid
+    ///
+    /// ```js
+    /// let foo;
+    /// const {foo} = bar;
+    /// function foo() {
+    ///   return;
+    /// }
+    /// function* foo() {
+    ///   yield;
+    /// }
+    /// function foo(bar) {}
+    /// function foo({bar}) {}
+    /// foo();
+    /// ```
+    ///
+    pub NoUselessUndefined {
+        version: "next",
+        name: "noUselessUndefined",
+        language: "js",
+        fix_kind: FixKind::Safe,
+        sources: &[RuleSource::EslintUnicorn("no-useless-undefined")],
+        recommended: false,
+    }
+}
+
+declare_node_union! {
+    pub AnyUndefinedNode = JsVariableStatement
+        | JsObjectBindingPatternShorthandProperty
+        | JsYieldArgument
+        | JsReturnStatement
+        | JsArrayBindingPatternElement
+        | JsArrowFunctionExpression
+        | JsFormalParameter
+}
+
+fn find_undefined_range(expr: Option<&AnyJsExpression>) -> Option<TextRange> {
+    let ident = expr?.as_js_reference_identifier()?;
+    if ident.is_undefined() {
+        Some(ident.range())
+    } else {
+        None
+    }
+}
+
+pub struct RuleState {
+    binding_text: Option<TokenText>,
+    diagnostic_range: TextRange,
+}
+
+impl Rule for NoUselessUndefined {
+    type Query = Ast<AnyUndefinedNode>;
+    type State = RuleState;
+    type Signals = Box<[Self::State]>;
+    type Options = ();
+
+    fn run(ctx: &RuleContext<Self>) -> Self::Signals {
+        let node = ctx.query();
+        let mut signals = vec![];
+
+        match node {
+            // let foo = undefined;
+            AnyUndefinedNode::JsVariableStatement(statement) => {
+                let Ok(node) = statement.declaration() else {
+                    return signals.into_boxed_slice();
+                };
+                let let_or_var = node.is_let() || node.is_var();
+                if !let_or_var {
+                    return signals.into_boxed_slice();
+                }
+
+                for declarator in node.declarators() {
+                    let Ok(decl) = declarator else { continue };
+                    let Some(initializer) = decl.initializer() else {
+                        continue;
+                    };
+                    let expr = initializer.expression().ok();
+                    if let Some(undefined_range) = find_undefined_range(expr.as_ref()) {
+                        let Ok(binding_text) = decl.id() else {
+                            continue;
+                        };
+                        if let Some(binding) = binding_text.as_any_js_binding() {
+                            if let Some(ident_binding) = binding.as_js_identifier_binding() {
+                                let binding_text = ident_binding
+                                    .name_token()
+                                    .map(|t| t.token_text_trimmed())
+                                    .ok();
+                                signals.push(RuleState {
+                                    binding_text,
+                                    diagnostic_range: undefined_range,
+                                });
+                            }
+                        }
+                    }
+                }
+            }
+            // { a: undefined }
+            AnyUndefinedNode::JsObjectBindingPatternShorthandProperty(
+                js_object_binding_pattern_shorthand_property,
+            ) => {
+                if let Some(init) = js_object_binding_pattern_shorthand_property.init() {
+                    let expr = init.expression().ok();
+                    if let Some(range) = find_undefined_range(expr.as_ref()) {
+                        signals.push(RuleState {
+                            binding_text: None,
+                            diagnostic_range: range,
+                        });
+                    }
+                }
+            }
+            // function foo([bar = undefined]) {}
+            AnyUndefinedNode::JsArrayBindingPatternElement(js_array_binding_pattern_element) => {
+                if let Some(init) = js_array_binding_pattern_element.init() {
+                    let expr = init.expression().ok();
+                    if let Some(range) = find_undefined_range(expr.as_ref()) {
+                        signals.push(RuleState {
+                            binding_text: None,
+                            diagnostic_range: range,
+                        });
+                    }
+                }
+            }
+            // yield undefined
+            AnyUndefinedNode::JsYieldArgument(yield_argument) => {
+                if yield_argument.star_token().is_some() {
+                    return signals.into_boxed_slice();
+                }
+                let expr = yield_argument.expression().ok();
+                if let Some(range) = find_undefined_range(expr.as_ref()) {
+                    signals.push(RuleState {
+                        binding_text: None,
+                        diagnostic_range: range,
+                    });
+                }
+            }
+            // return undefined
+            AnyUndefinedNode::JsReturnStatement(js_return_statement) => {
+                let expr = js_return_statement.argument();
+                if let Some(range) = find_undefined_range(expr.as_ref()) {
+                    signals.push(RuleState {
+                        binding_text: None,
+                        diagnostic_range: range,
+                    });
+                }
+            }
+            // const noop = () => undefined
+            AnyUndefinedNode::JsArrowFunctionExpression(js_arrow_function_expression) => {
+                if let Ok(body) = js_arrow_function_expression.body() {
+                    let expr = body.as_any_js_expression();
+                    if let Some(range) = find_undefined_range(expr) {
+                        signals.push(RuleState {
+                            binding_text: None,
+                            diagnostic_range: range,
+                        });
+                    }
+                }
+            }
+            // function foo(bar = undefined) {}
+            AnyUndefinedNode::JsFormalParameter(js_formal_parameter) => {
+                if let Some(init) = js_formal_parameter.initializer() {
+                    let expr = init.expression().ok();
+                    if let Some(range) = find_undefined_range(expr.as_ref()) {
+                        signals.push(RuleState {
+                            binding_text: None,
+                            diagnostic_range: range,
+                        });
+                    }
+                }
+            }
+        };
+
+        signals.into_boxed_slice()
+    }
+
+    fn diagnostic(_ctx: &RuleContext<Self>, state: &Self::State) -> Option<RuleDiagnostic> {
+        Some(
+            RuleDiagnostic::new(
+                rule_category!(),
+                state.diagnostic_range,
+                markup! {
+                    "Don't use unnecessary "<Emphasis>"undefined"</Emphasis>"."
+                },
+            )
+            .note(markup! {
+                ""<Emphasis>"undefined"</Emphasis>" is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference."
+            }),
+        )
+    }
+
+    fn action(ctx: &RuleContext<Self>, state: &Self::State) -> Option<JsRuleAction> {
+        let node = ctx.query();
+        let mut mutation = ctx.root().begin();
+
+        match node {
+            AnyUndefinedNode::JsVariableStatement(js_variable_statement) => {
+                let current_declaration_statement = js_variable_statement.declaration().ok()?;
+                let declarators = current_declaration_statement.declarators();
+
+                let current_declaration =
+                    declarators
+                        .into_iter()
+                        .filter_map(Result::ok)
+                        .find(|decl| {
+                            decl.id().is_ok_and(|id| {
+                                id.text() == state.binding_text.as_deref().unwrap_or("")
+                            })
+                        })?;
+
+                let current_initializer = current_declaration.initializer()?;
+                mutation.remove_node(current_initializer);
+            }
+            AnyUndefinedNode::JsObjectBindingPatternShorthandProperty(property) => {
+                mutation.remove_node(property.init()?);
+            }
+            AnyUndefinedNode::JsYieldArgument(yield_argument) => {
+                mutation.remove_node(yield_argument.expression().ok()?);
+            }
+            AnyUndefinedNode::JsReturnStatement(return_statement) => {
+                mutation.remove_node(return_statement.argument()?);
+            }
+            AnyUndefinedNode::JsArrayBindingPatternElement(pattern_element) => {
+                let init = pattern_element.init()?;
+                mutation.remove_node(init)
+            }
+            AnyUndefinedNode::JsArrowFunctionExpression(js_arrow_function_expression) => {
+                let undefined_body = js_arrow_function_expression.body().ok()?;
+                let next_node = js_function_body(
+                    make::token(T!['{']),
+                    make::js_directive_list(None),
+                    make::js_statement_list(None),
+                    make::token(T!['}']),
+                );
+                mutation.replace_node_discard_trivia(
+                    undefined_body,
+                    AnyJsFunctionBody::JsFunctionBody(next_node),
+                );
+            }
+            AnyUndefinedNode::JsFormalParameter(js_formal_parameter) => {
+                let init = js_formal_parameter.initializer()?;
+                mutation.remove_node(init);
+            }
+        };
+
+        Some(JsRuleAction::new(
+            ActionCategory::QuickFix,
+            ctx.metadata().applicability(),
+            markup! { "Remove the undefined."}.to_owned(),
+            mutation,
+        ))
+    }
+}
diff --git a/crates/biome_js_analyze/src/options.rs b/crates/biome_js_analyze/src/options.rs
index eba192f87e62..39938886cd81 100644
--- a/crates/biome_js_analyze/src/options.rs
+++ b/crates/biome_js_analyze/src/options.rs
@@ -267,6 +267,8 @@ pub type NoUselessTernary =
 pub type NoUselessThisAlias =
     <lint::complexity::no_useless_this_alias::NoUselessThisAlias as biome_analyze::Rule>::Options;
 pub type NoUselessTypeConstraint = < lint :: complexity :: no_useless_type_constraint :: NoUselessTypeConstraint as biome_analyze :: Rule > :: Options ;
+pub type NoUselessUndefined =
+    <lint::nursery::no_useless_undefined::NoUselessUndefined as biome_analyze::Rule>::Options;
 pub type NoUselessUndefinedInitialization = < lint :: complexity :: no_useless_undefined_initialization :: NoUselessUndefinedInitialization as biome_analyze :: Rule > :: Options ;
 pub type NoVar = <lint::style::no_var::NoVar as biome_analyze::Rule>::Options;
 pub type NoVoid = <lint::complexity::no_void::NoVoid as biome_analyze::Rule>::Options;
diff --git a/crates/biome_unicode_table/src/tables.rs b/crates/biome_unicode_table/src/tables.rs
index 2016f15b83d8..2521478eca81 100644
--- a/crates/biome_unicode_table/src/tables.rs
+++ b/crates/biome_unicode_table/src/tables.rs
@@ -71,7 +71,7 @@ pub mod derived_property {
         ('ࡠ', 'ࡪ'),
         ('ࡰ', 'ࢇ'),
         ('ࢉ', 'ࢎ'),
-        ('\u{897}', '\u{8e1}'),
+        ('\u{898}', '\u{8e1}'),
         ('\u{8e3}', '\u{963}'),
         ('०', '९'),
         ('ॱ', 'ঃ'),
@@ -294,7 +294,7 @@ pub mod derived_property {
         ('ᰀ', '\u{1c37}'),
         ('᱀', '᱉'),
         ('ᱍ', 'ᱽ'),
-        ('ᲀ', '\u{1c8a}'),
+        ('ᲀ', 'ᲈ'),
         ('Ა', 'Ჺ'),
         ('Ჽ', 'Ჿ'),
         ('\u{1cd0}', '\u{1cd2}'),
@@ -378,10 +378,10 @@ pub mod derived_property {
         ('ꙿ', '\u{a6f1}'),
         ('ꜗ', 'ꜟ'),
         ('Ꜣ', 'ꞈ'),
-        ('Ꞌ', '\u{a7cd}'),
+        ('Ꞌ', 'ꟊ'),
         ('Ꟑ', 'ꟑ'),
         ('ꟓ', 'ꟓ'),
-        ('ꟕ', '\u{a7dc}'),
+        ('ꟕ', 'ꟙ'),
         ('ꟲ', 'ꠧ'),
         ('\u{a82c}', '\u{a82c}'),
         ('ꡀ', 'ꡳ'),
@@ -479,7 +479,6 @@ pub mod derived_property {
         ('𐖣', '𐖱'),
         ('𐖳', '𐖹'),
         ('𐖻', '𐖼'),
-        ('\u{105c0}', '\u{105f3}'),
         ('𐘀', '𐜶'),
         ('𐝀', '𐝕'),
         ('𐝠', '𐝧'),
@@ -520,14 +519,10 @@ pub mod derived_property {
         ('𐳀', '𐳲'),
         ('𐴀', '\u{10d27}'),
         ('𐴰', '𐴹'),
-        ('\u{10d40}', '\u{10d65}'),
-        ('\u{10d69}', '\u{10d6d}'),
-        ('\u{10d6f}', '\u{10d85}'),
         ('𐺀', '𐺩'),
         ('\u{10eab}', '\u{10eac}'),
         ('𐺰', '𐺱'),
-        ('\u{10ec2}', '\u{10ec4}'),
-        ('\u{10efc}', '𐼜'),
+        ('\u{10efd}', '𐼜'),
         ('𐼧', '𐼧'),
         ('𐼰', '\u{10f50}'),
         ('𐽰', '\u{10f85}'),
@@ -573,16 +568,6 @@ pub mod derived_property {
         ('𑍝', '𑍣'),
         ('\u{11366}', '\u{1136c}'),
         ('\u{11370}', '\u{11374}'),
-        ('\u{11380}', '\u{11389}'),
-        ('\u{1138b}', '\u{1138b}'),
-        ('\u{1138e}', '\u{1138e}'),
-        ('\u{11390}', '\u{113b5}'),
-        ('\u{113b7}', '\u{113c0}'),
-        ('\u{113c2}', '\u{113c2}'),
-        ('\u{113c5}', '\u{113c5}'),
-        ('\u{113c7}', '\u{113ca}'),
-        ('\u{113cc}', '\u{113d3}'),
-        ('\u{113e1}', '\u{113e2}'),
         ('𑐀', '𑑊'),
         ('𑑐', '𑑙'),
         ('\u{1145e}', '𑑡'),
@@ -597,7 +582,6 @@ pub mod derived_property {
         ('𑙐', '𑙙'),
         ('𑚀', '𑚸'),
         ('𑛀', '𑛉'),
-        ('\u{116d0}', '\u{116e3}'),
         ('𑜀', '𑜚'),
         ('\u{1171d}', '\u{1172b}'),
         ('𑜰', '𑜹'),
@@ -621,8 +605,6 @@ pub mod derived_property {
         ('𑩐', '\u{11a99}'),
         ('𑪝', '𑪝'),
         ('𑪰', '𑫸'),
-        ('\u{11bc0}', '\u{11be0}'),
-        ('\u{11bf0}', '\u{11bf9}'),
         ('𑰀', '𑰈'),
         ('𑰊', '\u{11c36}'),
         ('\u{11c38}', '𑱀'),
@@ -647,7 +629,7 @@ pub mod derived_property {
         ('\u{11f00}', '𑼐'),
         ('𑼒', '\u{11f3a}'),
         ('𑼾', '\u{11f42}'),
-        ('𑽐', '\u{11f5a}'),
+        ('𑽐', '𑽙'),
         ('𑾰', '𑾰'),
         ('𒀀', '𒎙'),
         ('𒐀', '𒑮'),
@@ -655,9 +637,7 @@ pub mod derived_property {
         ('𒾐', '𒿰'),
         ('𓀀', '𓐯'),
         ('\u{13440}', '\u{13455}'),
-        ('\u{13460}', '\u{143fa}'),
         ('𔐀', '𔙆'),
-        ('\u{16100}', '\u{16139}'),
         ('𖠀', '𖨸'),
         ('𖩀', '𖩞'),
         ('𖩠', '𖩩'),
@@ -670,8 +650,6 @@ pub mod derived_property {
         ('𖭐', '𖭙'),
         ('𖭣', '𖭷'),
         ('𖭽', '𖮏'),
-        ('\u{16d40}', '\u{16d6c}'),
-        ('\u{16d70}', '\u{16d79}'),
         ('𖹀', '𖹿'),
         ('𖼀', '𖽊'),
         ('\u{16f4f}', '𖾇'),
@@ -681,7 +659,7 @@ pub mod derived_property {
         ('𖿰', '𖿱'),
         ('𗀀', '𘟷'),
         ('𘠀', '𘳕'),
-        ('\u{18cff}', '𘴈'),
+        ('𘴀', '𘴈'),
         ('𚿰', '𚿳'),
         ('𚿵', '𚿻'),
         ('𚿽', '𚿾'),
@@ -696,7 +674,6 @@ pub mod derived_property {
         ('𛲀', '𛲈'),
         ('𛲐', '𛲙'),
         ('\u{1bc9d}', '\u{1bc9e}'),
-        ('\u{1ccf0}', '\u{1ccf9}'),
         ('\u{1cf00}', '\u{1cf2d}'),
         ('\u{1cf30}', '\u{1cf46}'),
         ('\u{1d165}', '\u{1d169}'),
@@ -758,7 +735,6 @@ pub mod derived_property {
         ('𞊐', '\u{1e2ae}'),
         ('𞋀', '𞋹'),
         ('𞓐', '𞓹'),
-        ('\u{1e5d0}', '\u{1e5fa}'),
         ('𞟠', '𞟦'),
         ('𞟨', '𞟫'),
         ('𞟭', '𞟮'),
@@ -1040,7 +1016,7 @@ pub mod derived_property {
         ('ᰀ', 'ᰣ'),
         ('ᱍ', 'ᱏ'),
         ('ᱚ', 'ᱽ'),
-        ('ᲀ', '\u{1c8a}'),
+        ('ᲀ', 'ᲈ'),
         ('Ა', 'Ჺ'),
         ('Ჽ', 'Ჿ'),
         ('ᳩ', 'ᳬ'),
@@ -1123,10 +1099,10 @@ pub mod derived_property {
         ('ꚠ', 'ꛯ'),
         ('ꜗ', 'ꜟ'),
         ('Ꜣ', 'ꞈ'),
-        ('Ꞌ', '\u{a7cd}'),
+        ('Ꞌ', 'ꟊ'),
         ('Ꟑ', 'ꟑ'),
         ('ꟓ', 'ꟓ'),
-        ('ꟕ', '\u{a7dc}'),
+        ('ꟕ', 'ꟙ'),
         ('ꟲ', 'ꠁ'),
         ('ꠃ', 'ꠅ'),
         ('ꠇ', 'ꠊ'),
@@ -1224,7 +1200,6 @@ pub mod derived_property {
         ('𐖣', '𐖱'),
         ('𐖳', '𐖹'),
         ('𐖻', '𐖼'),
-        ('\u{105c0}', '\u{105f3}'),
         ('𐘀', '𐜶'),
         ('𐝀', '𐝕'),
         ('𐝠', '𐝧'),
@@ -1261,11 +1236,8 @@ pub mod derived_property {
         ('𐲀', '𐲲'),
         ('𐳀', '𐳲'),
         ('𐴀', '𐴣'),
-        ('\u{10d4a}', '\u{10d65}'),
-        ('\u{10d6f}', '\u{10d85}'),
         ('𐺀', '𐺩'),
         ('𐺰', '𐺱'),
-        ('\u{10ec2}', '\u{10ec4}'),
         ('𐼀', '𐼜'),
         ('𐼧', '𐼧'),
         ('𐼰', '𐽅'),
@@ -1304,13 +1276,6 @@ pub mod derived_property {
         ('𑌽', '𑌽'),
         ('𑍐', '𑍐'),
         ('𑍝', '𑍡'),
-        ('\u{11380}', '\u{11389}'),
-        ('\u{1138b}', '\u{1138b}'),
-        ('\u{1138e}', '\u{1138e}'),
-        ('\u{11390}', '\u{113b5}'),
-        ('\u{113b7}', '\u{113b7}'),
-        ('\u{113d1}', '\u{113d1}'),
-        ('\u{113d3}', '\u{113d3}'),
         ('𑐀', '𑐴'),
         ('𑑇', '𑑊'),
         ('𑑟', '𑑡'),
@@ -1345,7 +1310,6 @@ pub mod derived_property {
         ('𑩜', '𑪉'),
         ('𑪝', '𑪝'),
         ('𑪰', '𑫸'),
-        ('\u{11bc0}', '\u{11be0}'),
         ('𑰀', '𑰈'),
         ('𑰊', '𑰮'),
         ('𑱀', '𑱀'),
@@ -1369,9 +1333,7 @@ pub mod derived_property {
         ('𒾐', '𒿰'),
         ('𓀀', '𓐯'),
         ('𓑁', '𓑆'),
-        ('\u{13460}', '\u{143fa}'),
         ('𔐀', '𔙆'),
-        ('\u{16100}', '\u{1611d}'),
         ('𖠀', '𖨸'),
         ('𖩀', '𖩞'),
         ('𖩰', '𖪾'),
@@ -1380,7 +1342,6 @@ pub mod derived_property {
         ('𖭀', '𖭃'),
         ('𖭣', '𖭷'),
         ('𖭽', '𖮏'),
-        ('\u{16d40}', '\u{16d6c}'),
         ('𖹀', '𖹿'),
         ('𖼀', '𖽊'),
         ('𖽐', '𖽐'),
@@ -1389,7 +1350,7 @@ pub mod derived_property {
         ('𖿣', '𖿣'),
         ('𗀀', '𘟷'),
         ('𘠀', '𘳕'),
-        ('\u{18cff}', '𘴈'),
+        ('𘴀', '𘴈'),
         ('𚿰', '𚿳'),
         ('𚿵', '𚿻'),
         ('𚿽', '𚿾'),
@@ -1442,8 +1403,6 @@ pub mod derived_property {
         ('𞊐', '𞊭'),
         ('𞋀', '𞋫'),
         ('𞓐', '𞓫'),
-        ('\u{1e5d0}', '\u{1e5ed}'),
-        ('\u{1e5f0}', '\u{1e5f0}'),
         ('𞟠', '𞟦'),
         ('𞟨', '𞟫'),
         ('𞟭', '𞟮'),
diff --git a/packages/@biomejs/backend-jsonrpc/src/workspace.ts b/packages/@biomejs/backend-jsonrpc/src/workspace.ts
index b4688cfefe0a..4bea6a98acd3 100644
--- a/packages/@biomejs/backend-jsonrpc/src/workspace.ts
+++ b/packages/@biomejs/backend-jsonrpc/src/workspace.ts
@@ -1338,6 +1338,10 @@ export interface Nursery {
 	 * Disallow unnecessary String.raw function in template string literals without any escape sequence.
 	 */
 	noUselessStringRaw?: RuleConfiguration_for_Null;
+	/**
+	 * Disallow the use of useless undefined.
+	 */
+	noUselessUndefined?: RuleFixConfiguration_for_Null;
 	/**
 	 * Disallow use of @value rule in css modules.
 	 */
@@ -2959,6 +2963,7 @@ export type Category =
 	| "lint/nursery/noUnusedFunctionParameters"
 	| "lint/nursery/noUselessEscapeInRegex"
 	| "lint/nursery/noUselessStringRaw"
+	| "lint/nursery/noUselessUndefined"
 	| "lint/nursery/noValueAtRule"
 	| "lint/nursery/useAdjacentOverloadSignatures"
 	| "lint/nursery/useAriaPropsSupportedByRole"
diff --git a/packages/@biomejs/biome/configuration_schema.json b/packages/@biomejs/biome/configuration_schema.json
index a6865f922768..a6ba2d58a8dd 100644
--- a/packages/@biomejs/biome/configuration_schema.json
+++ b/packages/@biomejs/biome/configuration_schema.json
@@ -2295,6 +2295,13 @@
 						{ "type": "null" }
 					]
 				},
+				"noUselessUndefined": {
+					"description": "Disallow the use of useless undefined.",
+					"anyOf": [
+						{ "$ref": "#/definitions/RuleFixConfiguration" },
+						{ "type": "null" }
+					]
+				},
 				"noValueAtRule": {
 					"description": "Disallow use of @value rule in css modules.",
 					"anyOf": [


Test patch:
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noUselessUndefined/invalid.json b/crates/biome_js_analyze/tests/specs/nursery/noUselessUndefined/invalid.json
new file mode 100644
index 000000000000..8b567c5169a8
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noUselessUndefined/invalid.json
@@ -0,0 +1,25 @@
+[
+	"let a = undefined;",
+	"let a = undefined, b = 2;",
+	"var a = undefined;",
+	"var a = undefined, b = 2;",
+
+	"function foo() {return undefined;}",
+
+	"const foo = () => undefined;",
+	"const foo = () => {return undefined;};",
+
+	"function foo() {return undefined;}",
+	"function foo() {return /* comment */ undefined;}",
+	"function* foo() {yield undefined;}",
+	"function* foo() {yield undefined;}",
+
+	"const {foo = undefined} = {};",
+	"const [foo = undefined] = [];",
+
+	"function foo(bar = undefined) {}",
+	"function foo({bar = undefined}) {}",
+	"function foo({bar = undefined} = {}) {}",
+	"function foo([bar = undefined]) {}",
+	"function foo([bar = undefined] = []) {}"
+]
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noUselessUndefined/invalid.json.snap b/crates/biome_js_analyze/tests/specs/nursery/noUselessUndefined/invalid.json.snap
new file mode 100644
index 000000000000..32e7312bd1e8
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noUselessUndefined/invalid.json.snap
@@ -0,0 +1,418 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: invalid.json
+---
+# Input
+```cjs
+let a = undefined;
+```
+
+# Diagnostics
+```
+invalid.json:1:9 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ let a = undefined;
+      │         ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ let·a·=·undefined;
+      │       ----------- 
+
+```
+
+# Input
+```cjs
+let a = undefined, b = 2;
+```
+
+# Diagnostics
+```
+invalid.json:1:9 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ let a = undefined, b = 2;
+      │         ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ let·a·=·undefined,·b·=·2;
+      │       -----------        
+
+```
+
+# Input
+```cjs
+var a = undefined;
+```
+
+# Diagnostics
+```
+invalid.json:1:9 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ var a = undefined;
+      │         ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ var·a·=·undefined;
+      │       ----------- 
+
+```
+
+# Input
+```cjs
+var a = undefined, b = 2;
+```
+
+# Diagnostics
+```
+invalid.json:1:9 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ var a = undefined, b = 2;
+      │         ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ var·a·=·undefined,·b·=·2;
+      │       -----------        
+
+```
+
+# Input
+```cjs
+function foo() {return undefined;}
+```
+
+# Diagnostics
+```
+invalid.json:1:24 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ function foo() {return undefined;}
+      │                        ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ function·foo()·{return·undefined;}
+      │                        ---------  
+
+```
+
+# Input
+```cjs
+const foo = () => undefined;
+```
+
+# Diagnostics
+```
+invalid.json:1:19 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ const foo = () => undefined;
+      │                   ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+  - const·foo·=·()·=>·undefined;
+  + const·foo·=·()·=>·{};
+  
+
+```
+
+# Input
+```cjs
+const foo = () => {return undefined;};
+```
+
+# Diagnostics
+```
+invalid.json:1:27 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ const foo = () => {return undefined;};
+      │                           ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ const·foo·=·()·=>·{return·undefined;};
+      │                           ---------   
+
+```
+
+# Input
+```cjs
+function foo() {return undefined;}
+```
+
+# Diagnostics
+```
+invalid.json:1:24 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ function foo() {return undefined;}
+      │                        ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ function·foo()·{return·undefined;}
+      │                        ---------  
+
+```
+
+# Input
+```cjs
+function foo() {return /* comment */ undefined;}
+```
+
+# Diagnostics
+```
+invalid.json:1:38 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ function foo() {return /* comment */ undefined;}
+      │                                      ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ function·foo()·{return·/*·comment·*/·undefined;}
+      │                                      ---------  
+
+```
+
+# Input
+```cjs
+function* foo() {yield undefined;}
+```
+
+# Diagnostics
+```
+invalid.json:1:24 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ function* foo() {yield undefined;}
+      │                        ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ function*·foo()·{yield·undefined;}
+      │                        ---------  
+
+```
+
+# Input
+```cjs
+function* foo() {yield undefined;}
+```
+
+# Diagnostics
+```
+invalid.json:1:24 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ function* foo() {yield undefined;}
+      │                        ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ function*·foo()·{yield·undefined;}
+      │                        ---------  
+
+```
+
+# Input
+```cjs
+const {foo = undefined} = {};
+```
+
+# Diagnostics
+```
+invalid.json:1:14 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ const {foo = undefined} = {};
+      │              ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ const·{foo·=·undefined}·=·{};
+      │            -----------       
+
+```
+
+# Input
+```cjs
+const [foo = undefined] = [];
+```
+
+# Diagnostics
+```
+invalid.json:1:14 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ const [foo = undefined] = [];
+      │              ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ const·[foo·=·undefined]·=·[];
+      │            -----------       
+
+```
+
+# Input
+```cjs
+function foo(bar = undefined) {}
+```
+
+# Diagnostics
+```
+invalid.json:1:20 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ function foo(bar = undefined) {}
+      │                    ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ function·foo(bar·=·undefined)·{}
+      │                  -----------    
+
+```
+
+# Input
+```cjs
+function foo({bar = undefined}) {}
+```
+
+# Diagnostics
+```
+invalid.json:1:21 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ function foo({bar = undefined}) {}
+      │                     ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ function·foo({bar·=·undefined})·{}
+      │                   -----------     
+
+```
+
+# Input
+```cjs
+function foo({bar = undefined} = {}) {}
+```
+
+# Diagnostics
+```
+invalid.json:1:21 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ function foo({bar = undefined} = {}) {}
+      │                     ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ function·foo({bar·=·undefined}·=·{})·{}
+      │                   -----------          
+
+```
+
+# Input
+```cjs
+function foo([bar = undefined]) {}
+```
+
+# Diagnostics
+```
+invalid.json:1:21 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ function foo([bar = undefined]) {}
+      │                     ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ function·foo([bar·=·undefined])·{}
+      │                   -----------     
+
+```
+
+# Input
+```cjs
+function foo([bar = undefined] = []) {}
+```
+
+# Diagnostics
+```
+invalid.json:1:21 lint/nursery/noUselessUndefined  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use unnecessary undefined.
+  
+  > 1 │ function foo([bar = undefined] = []) {}
+      │                     ^^^^^^^^^
+  
+  i undefined is the default value for new variables, parameters, return statements, etc… so specifying it doesn't make any difference.
+  
+  i Safe fix: Remove the undefined.
+  
+    1 │ function·foo([bar·=·undefined]·=·[])·{}
+      │                   -----------          
+
+```
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noUselessUndefined/valid.json b/crates/biome_js_analyze/tests/specs/nursery/noUselessUndefined/valid.json
new file mode 100644
index 000000000000..95c1e71b47d4
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noUselessUndefined/valid.json
@@ -0,0 +1,54 @@
+[
+	"function foo() {return;}",
+	"const foo = () => {};",
+	"let foo;",
+	"var foo;",
+	"const foo = undefined;",
+	"foo();",
+	"foo(bar,);",
+	"foo(undefined, bar);",
+	"const {foo} = {};",
+	"function foo({bar} = {}) {}",
+	"function foo(bar) {}",
+	"function* foo() {yield* undefined;}",
+	"if (Object.is(foo, undefined)){}",
+	"t.is(foo, undefined)",
+	"assert.equal(foo, undefined, message)",
+	"assert.notEqual(foo, undefined, message)",
+	"assert.strictEqual(foo, undefined, message)",
+	"assert.notStrictEqual(foo, undefined, message)",
+	"assert.propertyVal(foo, 'bar', undefined, message)",
+	"assert.notPropertyVal(foo, 'bar', undefined, message)",
+	"expect(foo).not(undefined)",
+	"expect(foo).to.have.property('bar', undefined)",
+	"expect(foo).toBe(undefined)",
+	"expect(foo).toContain(undefined)",
+	"expect(foo).toContainEqual(undefined)",
+	"expect(foo).toEqual(undefined)",
+	"t.same(foo, undefined)",
+	"t.notSame(foo, undefined)",
+	"t.strictSame(foo, undefined)",
+	"t.strictNotSame(foo, undefined)",
+	"expect(someFunction).toHaveBeenCalledWith(1, 2, undefined);",
+	"set.add(undefined);",
+	"map.set(foo, undefined);",
+	"array.push(foo, undefined);",
+	"array.push(undefined);",
+	"array.unshift(foo, undefined);",
+	"array.unshift(undefined);",
+	"createContext(undefined);",
+	"React.createContext(undefined);",
+	"setState(undefined)",
+	"setState?.(undefined)",
+	"props.setState(undefined)",
+	"props.setState?.(undefined)",
+	"array.includes(undefined)",
+	"set.has(undefined)",
+	// `Function#bind()`
+	"foo.bind(bar, undefined)",
+	"foo.bind(...bar, undefined)",
+	"foo.bind(...[], undefined)",
+	"foo.bind(...[undefined], undefined)",
+	"foo.bind(bar, baz, undefined)",
+	"foo?.bind(bar, undefined)"
+]
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noUselessUndefined/valid.json.snap b/crates/biome_js_analyze/tests/specs/nursery/noUselessUndefined/valid.json.snap
new file mode 100644
index 000000000000..e84e57e03bc4
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noUselessUndefined/valid.json.snap
@@ -0,0 +1,258 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: valid.json
+---
+# Input
+```cjs
+function foo() {return;}
+```
+
+# Input
+```cjs
+const foo = () => {};
+```
+
+# Input
+```cjs
+let foo;
+```
+
+# Input
+```cjs
+var foo;
+```
+
+# Input
+```cjs
+const foo = undefined;
+```
+
+# Input
+```cjs
+foo();
+```
+
+# Input
+```cjs
+foo(bar,);
+```
+
+# Input
+```cjs
+foo(undefined, bar);
+```
+
+# Input
+```cjs
+const {foo} = {};
+```
+
+# Input
+```cjs
+function foo({bar} = {}) {}
+```
+
+# Input
+```cjs
+function foo(bar) {}
+```
+
+# Input
+```cjs
+function* foo() {yield* undefined;}
+```
+
+# Input
+```cjs
+if (Object.is(foo, undefined)){}
+```
+
+# Input
+```cjs
+t.is(foo, undefined)
+```
+
+# Input
+```cjs
+assert.equal(foo, undefined, message)
+```
+
+# Input
+```cjs
+assert.notEqual(foo, undefined, message)
+```
+
+# Input
+```cjs
+assert.strictEqual(foo, undefined, message)
+```
+
+# Input
+```cjs
+assert.notStrictEqual(foo, undefined, message)
+```
+
+# Input
+```cjs
+assert.propertyVal(foo, 'bar', undefined, message)
+```
+
+# Input
+```cjs
+assert.notPropertyVal(foo, 'bar', undefined, message)
+```
+
+# Input
+```cjs
+expect(foo).not(undefined)
+```
+
+# Input
+```cjs
+expect(foo).to.have.property('bar', undefined)
+```
+
+# Input
+```cjs
+expect(foo).toBe(undefined)
+```
+
+# Input
+```cjs
+expect(foo).toContain(undefined)
+```
+
+# Input
+```cjs
+expect(foo).toContainEqual(undefined)
+```
+
+# Input
+```cjs
+expect(foo).toEqual(undefined)
+```
+
+# Input
+```cjs
+t.same(foo, undefined)
+```
+
+# Input
+```cjs
+t.notSame(foo, undefined)
+```
+
+# Input
+```cjs
+t.strictSame(foo, undefined)
+```
+
+# Input
+```cjs
+t.strictNotSame(foo, undefined)
+```
+
+# Input
+```cjs
+expect(someFunction).toHaveBeenCalledWith(1, 2, undefined);
+```
+
+# Input
+```cjs
+set.add(undefined);
+```
+
+# Input
+```cjs
+map.set(foo, undefined);
+```
+
+# Input
+```cjs
+array.push(foo, undefined);
+```
+
+# Input
+```cjs
+array.push(undefined);
+```
+
+# Input
+```cjs
+array.unshift(foo, undefined);
+```
+
+# Input
+```cjs
+array.unshift(undefined);
+```
+
+# Input
+```cjs
+createContext(undefined);
+```
+
+# Input
+```cjs
+React.createContext(undefined);
+```
+
+# Input
+```cjs
+setState(undefined)
+```
+
+# Input
+```cjs
+setState?.(undefined)
+```
+
+# Input
+```cjs
+props.setState(undefined)
+```
+
+# Input
+```cjs
+props.setState?.(undefined)
+```
+
+# Input
+```cjs
+array.includes(undefined)
+```
+
+# Input
+```cjs
+set.has(undefined)
+```
+
+# Input
+```cjs
+foo.bind(bar, undefined)
+```
+
+# Input
+```cjs
+foo.bind(...bar, undefined)
+```
+
+# Input
+```cjs
+foo.bind(...[], undefined)
+```
+
+# Input
+```cjs
+foo.bind(...[undefined], undefined)
+```
+
+# Input
+```cjs
+foo.bind(bar, baz, undefined)
+```
+
+# Input
+```cjs
+foo?.bind(bar, undefined)
+```