From 86acf977b17d2f62fc07f8f0202a8d3e43441c6a Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Tue, 31 Jan 2023 17:27:18 +0800 Subject: [PATCH 1/5] fix: paren shouldn't be removed from infer func --- changelog_unreleased/typescript/14279.md | 16 ++++++ src/language-js/needs-parens.js | 16 ++++-- .../__snapshots__/jsfmt.spec.js.snap | 54 ++++++++++++++----- .../conditional-types/issue-13275.ts | 1 - .../conditional-types/parentheses.ts | 14 +++++ 5 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 changelog_unreleased/typescript/14279.md delete mode 100644 tests/format/typescript/conditional-types/issue-13275.ts create mode 100644 tests/format/typescript/conditional-types/parentheses.ts diff --git a/changelog_unreleased/typescript/14279.md b/changelog_unreleased/typescript/14279.md new file mode 100644 index 000000000000..b15c9c37e649 --- /dev/null +++ b/changelog_unreleased/typescript/14279.md @@ -0,0 +1,16 @@ +#### Fix parens in inferred function return types with `extends` (#14279 by @fisker) + + +```ts +// Input +type Foo = T extends ((a) => a is infer R extends string) ? R : never; + +// Prettier stable (First format) +type Foo = T extends (a) => a is infer R extends string ? R : never; + +// Prettier stable (Second format) +SyntaxError: '?' expected. + +// Prettier main +type Foo = T extends ((a) => a is infer R extends string) ? R : never; +``` diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index 0fd0207dbf47..d669c28daa8b 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -473,15 +473,23 @@ function needsParens(path, options) { case "TSFunctionType": case "TSConstructorType": if (name === "extendsType" && parent.type === "TSConditionalType") { - const returnTypeAnnotation = (node.returnType || node.typeAnnotation) - .typeAnnotation; + 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; } diff --git a/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap index e598947c2b6a..c6daa2b22c2e 100644 --- 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 extends (infer U)[] ================================================================================ `; -exports[`issue-13275.ts format 1`] = ` -====================================options===================================== -parsers: ["typescript"] -printWidth: 80 - | printWidth -=====================================input====================================== -type Foo = T extends ((...a: any[]) => infer R extends string) ? R : never; - -=====================================output===================================== -type Foo = T extends ((...a: any[]) => infer R extends string) ? R : never; - -================================================================================ -`; - exports[`nested-in-condition.ts format 1`] = ` ====================================options===================================== parsers: ["typescript"] @@ -431,3 +417,43 @@ type Unpacked = T extends (infer U)[] ================================================================================ `; + +exports[`parentheses.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +// #13275 +type Foo = T extends ((...a: any[]) => infer R extends string) ? R : never; + +// #14275 +type Test = T extends (( + token: TSESTree.Token +) => token is infer U extends TSESTree.Token) + ? U + : TSESTree.Token; +type Test = T extends (( + token: TSESTree.Token +) => asserts token is infer U extends TSESTree.Token) + ? U + : TSESTree.Token; + +=====================================output===================================== +// #13275 +type Foo = T extends ((...a: any[]) => infer R extends string) ? R : never; + +// #14275 +type Test = T extends (( + token: TSESTree.Token +) => token is infer U extends TSESTree.Token) + ? U + : TSESTree.Token; +type Test = T extends (( + token: TSESTree.Token +) => asserts 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 index de1ccb2859aa..000000000000 --- a/tests/format/typescript/conditional-types/issue-13275.ts +++ /dev/null @@ -1 +0,0 @@ -type Foo = 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 index 000000000000..6ab38e197e73 --- /dev/null +++ b/tests/format/typescript/conditional-types/parentheses.ts @@ -0,0 +1,14 @@ +// #13275 +type Foo = T extends ((...a: any[]) => infer R extends string) ? R : never; + +// #14275 +type Test = T extends (( + token: TSESTree.Token +) => token is infer U extends TSESTree.Token) + ? U + : TSESTree.Token; +type Test = T extends (( + token: TSESTree.Token +) => asserts token is infer U extends TSESTree.Token) + ? U + : TSESTree.Token; From ffe71f8f8724398d34133cec51f64adfbf1fab9e Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Tue, 31 Jan 2023 17:48:16 +0800 Subject: [PATCH 2/5] Simplify logic --- src/language-js/needs-parens.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index d669c28daa8b..6155f0a7999d 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -466,13 +466,13 @@ 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") { + if (node.type === "TSConditionalType") { + return true; + } + let { typeAnnotation } = node.returnType || node.typeAnnotation; if ( From 467a1588c4a8d39740da409394b37d13ef9faf6f Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Tue, 31 Jan 2023 17:48:49 +0800 Subject: [PATCH 3/5] Test `TSConstructorType` --- .../__snapshots__/jsfmt.spec.js.snap | 14 ++++++++++++++ .../typescript/conditional-types/parentheses.ts | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap index c6daa2b22c2e..14c69d952f8f 100644 --- a/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap @@ -426,6 +426,7 @@ printWidth: 80 =====================================input====================================== // #13275 type Foo = T extends ((...a: any[]) => infer R extends string) ? R : never; +type Foo = T extends (new (...a: any[]) => infer R extends string) ? R : never; // #14275 type Test = T extends (( @@ -438,10 +439,18 @@ type Test = T extends (( ) => asserts token is infer U extends TSESTree.Token) ? U : TSESTree.Token; +type Test = T extends (new ( + token: TSESTree.Token +) => token is infer U extends TSESTree.Token) + ? U + : TSESTree.Token; =====================================output===================================== // #13275 type Foo = T extends ((...a: any[]) => infer R extends string) ? R : never; +type Foo = T extends (new (...a: any[]) => infer R extends string) + ? R + : never; // #14275 type Test = T extends (( @@ -454,6 +463,11 @@ type Test = T extends (( ) => asserts token is infer U extends TSESTree.Token) ? U : TSESTree.Token; +type Test = T extends (new ( + token: TSESTree.Token +) => token is infer U extends TSESTree.Token) + ? U + : TSESTree.Token; ================================================================================ `; diff --git a/tests/format/typescript/conditional-types/parentheses.ts b/tests/format/typescript/conditional-types/parentheses.ts index 6ab38e197e73..ea27b6710564 100644 --- a/tests/format/typescript/conditional-types/parentheses.ts +++ b/tests/format/typescript/conditional-types/parentheses.ts @@ -1,5 +1,6 @@ // #13275 type Foo = T extends ((...a: any[]) => infer R extends string) ? R : never; +type Foo = T extends (new (...a: any[]) => infer R extends string) ? R : never; // #14275 type Test = T extends (( @@ -12,3 +13,8 @@ type Test = T extends (( ) => asserts token is infer U extends TSESTree.Token) ? U : TSESTree.Token; +type Test = T extends (new ( + token: TSESTree.Token +) => token is infer U extends TSESTree.Token) + ? U + : TSESTree.Token; From ac1aac1146d57317cbfc4edebe2907f7fd9b238e Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Tue, 31 Jan 2023 19:18:17 +0800 Subject: [PATCH 4/5] Put more stuff inside --- .../__snapshots__/jsfmt.spec.js.snap | 16 ++++++++++++++++ .../typescript/conditional-types/parentheses.ts | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap index 14c69d952f8f..fcdbd56328d2 100644 --- a/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap @@ -428,6 +428,13 @@ printWidth: 80 type Foo = T extends ((...a: any[]) => infer R extends string) ? R : never; type Foo = T extends (new (...a: any[]) => infer R extends string) ? R : never; +// Nest +type Foo = T extends ( + (...a: any[]) => infer R extends ( + T extends ((...a: any[]) => infer R extends string) ? R : never + ) +) ? R : never; + // #14275 type Test = T extends (( token: TSESTree.Token @@ -452,6 +459,15 @@ type Foo = T extends (new (...a: any[]) => infer R extends string) ? R : never; +// Nest +type Foo = T extends (( + ...a: any[] +) => infer R extends T extends ((...a: any[]) => infer R extends string) + ? R + : never) + ? R + : never; + // #14275 type Test = T extends (( token: TSESTree.Token diff --git a/tests/format/typescript/conditional-types/parentheses.ts b/tests/format/typescript/conditional-types/parentheses.ts index ea27b6710564..db1e63e9a87a 100644 --- a/tests/format/typescript/conditional-types/parentheses.ts +++ b/tests/format/typescript/conditional-types/parentheses.ts @@ -2,6 +2,13 @@ type Foo = T extends ((...a: any[]) => infer R extends string) ? R : never; type Foo = T extends (new (...a: any[]) => infer R extends string) ? R : never; +// Nest +type Foo = T extends ( + (...a: any[]) => infer R extends ( + T extends ((...a: any[]) => infer R extends string) ? R : never + ) +) ? R : never; + // #14275 type Test = T extends (( token: TSESTree.Token From 6117e1b737fffe040fb4f50fe11bf00023324820 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Tue, 31 Jan 2023 19:31:30 +0800 Subject: [PATCH 5/5] Revert "Put more stuff inside" This reverts commit ac1aac1146d57317cbfc4edebe2907f7fd9b238e. --- .../__snapshots__/jsfmt.spec.js.snap | 16 ---------------- .../typescript/conditional-types/parentheses.ts | 7 ------- 2 files changed, 23 deletions(-) diff --git a/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap index fcdbd56328d2..14c69d952f8f 100644 --- a/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap @@ -428,13 +428,6 @@ printWidth: 80 type Foo = T extends ((...a: any[]) => infer R extends string) ? R : never; type Foo = T extends (new (...a: any[]) => infer R extends string) ? R : never; -// Nest -type Foo = T extends ( - (...a: any[]) => infer R extends ( - T extends ((...a: any[]) => infer R extends string) ? R : never - ) -) ? R : never; - // #14275 type Test = T extends (( token: TSESTree.Token @@ -459,15 +452,6 @@ type Foo = T extends (new (...a: any[]) => infer R extends string) ? R : never; -// Nest -type Foo = T extends (( - ...a: any[] -) => infer R extends T extends ((...a: any[]) => infer R extends string) - ? R - : never) - ? R - : never; - // #14275 type Test = T extends (( token: TSESTree.Token diff --git a/tests/format/typescript/conditional-types/parentheses.ts b/tests/format/typescript/conditional-types/parentheses.ts index db1e63e9a87a..ea27b6710564 100644 --- a/tests/format/typescript/conditional-types/parentheses.ts +++ b/tests/format/typescript/conditional-types/parentheses.ts @@ -2,13 +2,6 @@ type Foo = T extends ((...a: any[]) => infer R extends string) ? R : never; type Foo = T extends (new (...a: any[]) => infer R extends string) ? R : never; -// Nest -type Foo = T extends ( - (...a: any[]) => infer R extends ( - T extends ((...a: any[]) => infer R extends string) ? R : never - ) -) ? R : never; - // #14275 type Test = T extends (( token: TSESTree.Token