Repository: prettier/prettier (JavaScript)

Issue:
Incorrect removal of parentheses when using an `infer` with a constraint in a function predicate
**Prettier 2.8.3**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEMCeAHOACAKnAZxgB5cA+bAXj2zgA94oATA7ACjYB0ptsYIA1giR4AygFFRuAE5w4AOlyCE3AJRUK-ITwCWrHVABmcadgCqtBghZjJMuYuVRV3XgH5zr7CNwSpshSVtAG5uEAAaEAgMGB1oAmRQAENpaQgAdwAFFIQElCSAG3SktATIgCNpJLAhGFEkgFs4ABkDOGRDQoI4CqqauDqMaoMAc2QYaQBXHpA4BvK4JiZF5qSoEcmkkbgAMQhpBqSYWPXkECTJ-giQAAsYBoKAdRudeAIhsDhRXNedADdXmgzmACGUQAZutIYJkqiNDh0ujMAFYEOiiUYFOAARUmEHgCIK3UiQ2kkLO6CwBDA0h0MWuGBpsEeOiYMBuyAAHAAGYlpbqPKoYM4MwgmP7tSIAR1x8Bh0Ty5wIAFooHJlkxrrJpTpZDCtvCkJ1CTNug0dOMpiaMXAAILHGnlS5wTImVqqglEkAEa04vHtQ2IyIwJLlZms9lIABMQaqOgKowAwhAGgbZgQAKzXSbdXAhvJGz1-aYASWYCDq1NpMBtzFE6ExHrgAF8m0A)
<!-- prettier-ignore -->
```sh
--parser typescript
```

**Input:**
<!-- prettier-ignore -->
```tsx
type Test<T> = T extends ((
  token: TSESTree.Token
) => token is infer U extends TSESTree.Token)
  ? U
  : TSESTree.Token;

```

**Output:**
<!-- prettier-ignore -->
```tsx
type Test<T> = T extends (
  token: TSESTree.Token
) => token is infer U extends TSESTree.Token
  ? U
  : TSESTree.Token;

```

**Expected behavior:**
The parentheses should be retained as they are required.
Without the parentheses it causes a syntax error:
```
SyntaxError: '?' expected. (5:19)
  3 | ) => token is infer U extends TSESTree.Token
  4 |   ? U
> 5 |   : TSESTree.Token;
    |                   ^
  6 |
```


Hints:

Patch:
diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js
--- a/src/language-js/needs-parens.js
+++ b/src/language-js/needs-parens.js
@@ -466,22 +466,30 @@ function needsParens(path, options) {
       }
 
     case "TSConditionalType":
-      if (name === "extendsType" && parent.type === "TSConditionalType") {
-        return true;
-      }
-    // fallthrough
     case "TSFunctionType":
     case "TSConstructorType":
       if (name === "extendsType" && parent.type === "TSConditionalType") {
-        const returnTypeAnnotation = (node.returnType || node.typeAnnotation)
-          .typeAnnotation;
+        if (node.type === "TSConditionalType") {
+          return true;
+        }
+
+        let { typeAnnotation } = node.returnType || node.typeAnnotation;
+
+        if (
+          typeAnnotation.type === "TSTypePredicate" &&
+          typeAnnotation.typeAnnotation
+        ) {
+          typeAnnotation = typeAnnotation.typeAnnotation.typeAnnotation;
+        }
+
         if (
-          returnTypeAnnotation.type === "TSInferType" &&
-          returnTypeAnnotation.typeParameter.constraint
+          typeAnnotation.type === "TSInferType" &&
+          typeAnnotation.typeParameter.constraint
         ) {
           return true;
         }
       }
+
       if (name === "checkType" && parent.type === "TSConditionalType") {
         return true;
       }


Test patch:
diff --git a/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap
--- a/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap
@@ -278,20 +278,6 @@ type Unpacked<T> = T extends (infer U)[]
 ================================================================================
 `;
 
-exports[`issue-13275.ts format 1`] = `
-====================================options=====================================
-parsers: ["typescript"]
-printWidth: 80
-                                                                                | printWidth
-=====================================input======================================
-type Foo<T> = T extends ((...a: any[]) => infer R extends string) ? R : never;
-
-=====================================output=====================================
-type Foo<T> = T extends ((...a: any[]) => infer R extends string) ? R : never;
-
-================================================================================
-`;
-
 exports[`nested-in-condition.ts format 1`] = `
 ====================================options=====================================
 parsers: ["typescript"]
@@ -431,3 +417,57 @@ type Unpacked<T> = T extends (infer U)[]
 
 ================================================================================
 `;
+
+exports[`parentheses.ts format 1`] = `
+====================================options=====================================
+parsers: ["typescript"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+// #13275
+type Foo<T> = T extends ((...a: any[]) => infer R extends string) ? R : never;
+type Foo<T> = T extends (new (...a: any[]) => infer R extends string) ? R : never;
+
+// #14275
+type Test<T> = T extends ((
+  token: TSESTree.Token
+) => token is infer U extends TSESTree.Token)
+  ? U
+  : TSESTree.Token;
+type Test<T> = T extends ((
+  token: TSESTree.Token
+) => asserts token is infer U extends TSESTree.Token)
+  ? U
+  : TSESTree.Token;
+type Test<T> = T extends (new (
+  token: TSESTree.Token
+) => token is infer U extends TSESTree.Token)
+  ? U
+  : TSESTree.Token;
+
+=====================================output=====================================
+// #13275
+type Foo<T> = T extends ((...a: any[]) => infer R extends string) ? R : never;
+type Foo<T> = T extends (new (...a: any[]) => infer R extends string)
+  ? R
+  : never;
+
+// #14275
+type Test<T> = T extends ((
+  token: TSESTree.Token
+) => token is infer U extends TSESTree.Token)
+  ? U
+  : TSESTree.Token;
+type Test<T> = T extends ((
+  token: TSESTree.Token
+) => asserts token is infer U extends TSESTree.Token)
+  ? U
+  : TSESTree.Token;
+type Test<T> = T extends (new (
+  token: TSESTree.Token
+) => token is infer U extends TSESTree.Token)
+  ? U
+  : TSESTree.Token;
+
+================================================================================
+`;
diff --git a/tests/format/typescript/conditional-types/issue-13275.ts b/tests/format/typescript/conditional-types/issue-13275.ts
deleted file mode 100644
--- a/tests/format/typescript/conditional-types/issue-13275.ts
+++ /dev/null
@@ -1 +0,0 @@
-type Foo<T> = T extends ((...a: any[]) => infer R extends string) ? R : never;
diff --git a/tests/format/typescript/conditional-types/parentheses.ts b/tests/format/typescript/conditional-types/parentheses.ts
new file mode 100644
--- /dev/null
+++ b/tests/format/typescript/conditional-types/parentheses.ts
@@ -0,0 +1,20 @@
+// #13275
+type Foo<T> = T extends ((...a: any[]) => infer R extends string) ? R : never;
+type Foo<T> = T extends (new (...a: any[]) => infer R extends string) ? R : never;
+
+// #14275
+type Test<T> = T extends ((
+  token: TSESTree.Token
+) => token is infer U extends TSESTree.Token)
+  ? U
+  : TSESTree.Token;
+type Test<T> = T extends ((
+  token: TSESTree.Token
+) => asserts token is infer U extends TSESTree.Token)
+  ? U
+  : TSESTree.Token;
+type Test<T> = T extends (new (
+  token: TSESTree.Token
+) => token is infer U extends TSESTree.Token)
+  ? U
+  : TSESTree.Token;