Repository: eslint-stylistic/eslint-stylistic (ts)

Issue:
`no-extra-parens`: `v5.2.0` broke `nestedBinaryExpressions: false` for TypeScript
### Validations

- [x] Follow our [Code of Conduct](https://github.com/eslint-stylistic/eslint-stylistic/blob/main/CODE_OF_CONDUCT.md)
- [x] Read the [Contributing Guide](https://eslint.style/contribute/guide).
- [x] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

### Describe the bug

After upgrading to `v5.2.0`, `nestedBinaryExpressions: false` no longer works for TypeScript.
Looks like it's introduced by PR https://github.com/eslint-stylistic/eslint-stylistic/pull/873
<img width="816" height="347" alt="Image" src="https://github.com/user-attachments/assets/8caa0267-8983-41d3-9de6-99802f2207ba" />

### Reproduction

See above

### Contributes

- [ ] I am willing to submit a PR to fix this issue
- [ ] I am willing to submit a PR with failing tests

Pull request description:
fix(no-extra-parens): skip nested `TSUnionType/TSIntersectionType` when `nestedBinaryExpressions: false`
<!-- DO NOT IGNORE THE TEMPLATE!

Thank you for contributing!

Before submitting the PR, please make sure you do the following:

- Read the [Contributing Guide](https://eslint.style/contribute/guide).
- Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
- Provide a description in this PR that addresses **what** the PR is solving, or reference the issue that it solves (e.g. `fixes #123`).
- Ideally, include relevant tests that fail without this PR but pass with it.

-->

### Description

<!-- Please insert your description here and provide especially info about the "what" this PR is solving -->

### Linked Issues

Fixes #904 

### Additional context

<!-- e.g. is there anything you'd like reviewers to focus on? -->


Patch:
diff --git a/packages/eslint-plugin/rules/no-extra-parens/no-extra-parens.ts b/packages/eslint-plugin/rules/no-extra-parens/no-extra-parens.ts
index af73ab5d..06679e6c 100644
--- a/packages/eslint-plugin/rules/no-extra-parens/no-extra-parens.ts
+++ b/packages/eslint-plugin/rules/no-extra-parens/no-extra-parens.ts
@@ -11,6 +11,7 @@ import {
   isDecimalInteger,
   isKeywordToken,
   isMixedLogicalAndCoalesceExpressions,
+  isNodeOfTypes,
   isNotClosingParenToken,
   isNotOpeningParenToken,
   isOpeningBraceToken,
@@ -101,7 +102,7 @@ export default createRule<RuleOptions, MessageIds>({
       && context.options[1].conditionalAssign === false
     const EXCEPT_COND_TERNARY = ALL_NODES && context.options[1]
       && context.options[1].ternaryOperandBinaryExpressions === false
-    const NESTED_BINARY = ALL_NODES && context.options[1]
+    const IGNORE_NESTED_BINARY = ALL_NODES && context.options[1]
       && context.options[1].nestedBinaryExpressions === false
     const EXCEPT_RETURN_ASSIGN = ALL_NODES && context.options[1]
       && context.options[1].returnAssign === false
@@ -710,8 +711,8 @@ export default createRule<RuleOptions, MessageIds>({
         const leftPrecedence = precedence(n.left)
         const rightPrecedence = precedence(n.right)
         const isExponentiation = n.operator === '**'
-        const shouldSkipLeft = NESTED_BINARY && (n.left.type === 'BinaryExpression' || n.left.type === 'LogicalExpression')
-        const shouldSkipRight = NESTED_BINARY && (n.right.type === 'BinaryExpression' || n.right.type === 'LogicalExpression')
+        const shouldSkipLeft = IGNORE_NESTED_BINARY && (n.left.type === 'BinaryExpression' || n.left.type === 'LogicalExpression')
+        const shouldSkipRight = IGNORE_NESTED_BINARY && (n.right.type === 'BinaryExpression' || n.right.type === 'LogicalExpression')
 
         if (!shouldSkipLeft && hasExcessParens(n.left)) {
           if (
@@ -918,6 +919,17 @@ export default createRule<RuleOptions, MessageIds>({
         report(node.value)
     }
 
+    function checkTSBinaryType(node: Tree.TSUnionType | Tree.TSIntersectionType) {
+      node.types.forEach((type) => {
+        const shouldReport = IGNORE_NESTED_BINARY && isNodeOfTypes([AST_NODE_TYPES.TSUnionType, AST_NODE_TYPES.TSIntersectionType])(type)
+          ? isParenthesisedTwice(type)
+          : hasExcessParensWithPrecedence(type, precedence(node))
+
+        if (shouldReport)
+          report(type)
+      })
+    }
+
     return {
       ArrayExpression(node) {
         node.elements
@@ -1499,18 +1511,8 @@ export default createRule<RuleOptions, MessageIds>({
         if (hasExcessParensWithPrecedence(node.elementType, precedence(node)))
           report(node.elementType)
       },
-      TSIntersectionType(node) {
-        node.types.forEach((type) => {
-          if (hasExcessParensWithPrecedence(type, precedence(node)))
-            report(type)
-        })
-      },
-      TSUnionType(node) {
-        node.types.forEach((type) => {
-          if (hasExcessParensWithPrecedence(type, precedence(node)))
-            report(type)
-        })
-      },
+      'TSIntersectionType': checkTSBinaryType,
+      'TSUnionType': checkTSBinaryType,
       TSTypeAnnotation(node) {
         if (hasExcessParens(node.typeAnnotation)) {
           report(node.typeAnnotation)


Test patch:
diff --git a/packages/eslint-plugin/rules/no-extra-parens/no-extra-parens._ts_.test.ts b/packages/eslint-plugin/rules/no-extra-parens/no-extra-parens._ts_.test.ts
index 0d1bc541..68ea5f0a 100644
--- a/packages/eslint-plugin/rules/no-extra-parens/no-extra-parens._ts_.test.ts
+++ b/packages/eslint-plugin/rules/no-extra-parens/no-extra-parens._ts_.test.ts
@@ -361,6 +361,10 @@ run<RuleOptions, MessageIds>({
 
     `type Foo = string & (number | 'bar')`,
     `type Foo = (a extends string ? 'bar' : number)[]`,
+    {
+      code: `type Foo = boolean | (Bar & Baz)`,
+      options: ['all', { nestedBinaryExpressions: false }],
+    },
   ],
 
   invalid: [
@@ -547,5 +551,36 @@ run<RuleOptions, MessageIds>({
         { messageId: 'unexpected' },
       ],
     },
+    // https://github.com/eslint-stylistic/eslint-stylistic/issues/904
+    {
+      code: $`
+        type Foo = boolean | ((
+          & Bar
+          & Baz
+        ))
+      `,
+      output: $`
+        type Foo = boolean | (
+          & Bar
+          & Baz
+        )
+      `,
+      options: ['all', { nestedBinaryExpressions: false }],
+      errors: [
+        { messageId: 'unexpected' },
+      ],
+    },
+    {
+      code: $`
+        type Foo = boolean | ((Bar & Baz))
+      `,
+      output: $`
+        type Foo = boolean | Bar & Baz
+      `,
+      recursive: Number.POSITIVE_INFINITY,
+      errors: [
+        { messageId: 'unexpected' },
+      ],
+    },
   ],
 })