Skip to content

Commit

Permalink
Fix incorrect removal of parentheses when using an infer with a con…
Browse files Browse the repository at this point in the history
…straint in a function predicate (prettier#14279)
  • Loading branch information
fisker committed Feb 6, 2023
1 parent f602be5 commit bc18fa4
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 23 deletions.
16 changes: 16 additions & 0 deletions changelog_unreleased/typescript/14279.md
@@ -0,0 +1,16 @@
#### Fix parens in inferred function return types with `extends` (#14279 by @fisker)

<!-- prettier-ignore -->
```ts
// Input
type Foo<T> = T extends ((a) => a is infer R extends string) ? R : never;

// Prettier stable (First format)
type Foo<T> = T extends (a) => a is infer R extends string ? R : never;

// Prettier stable (Second format)
SyntaxError: '?' expected.

// Prettier main
type Foo<T> = T extends ((a) => a is infer R extends string) ? R : never;
```
24 changes: 16 additions & 8 deletions src/language-js/needs-parens.js
Expand Up @@ -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;
}
Expand Down
Expand Up @@ -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"]
Expand Down Expand Up @@ -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;
================================================================================
`;
1 change: 0 additions & 1 deletion tests/format/typescript/conditional-types/issue-13275.ts

This file was deleted.

20 changes: 20 additions & 0 deletions 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;

0 comments on commit bc18fa4

Please sign in to comment.