From 599bad14158a7815430662f96ecdd6d2e1f0fe54 Mon Sep 17 00:00:00 2001 From: Christopher Chedeau Date: Sat, 24 Jan 2026 13:03:35 -0800 Subject: [PATCH] Fix parenthesis for optional function as return type (#11004) Co-authored-by: fisker Cheung --- changelog_unreleased/flow/11004.md | 19 +++++++++++++ .../parentheses/needs-parentheses.js | 23 ++++++++++++++-- .../__snapshots__/format.test.js.snap | 27 +++++++++++++++++++ .../parenthesis-return-type/format.test.js | 1 + .../flow/parenthesis-return-type/optional.js | 7 +++++ 5 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 changelog_unreleased/flow/11004.md create mode 100644 tests/format/flow/parenthesis-return-type/__snapshots__/format.test.js.snap create mode 100644 tests/format/flow/parenthesis-return-type/format.test.js create mode 100644 tests/format/flow/parenthesis-return-type/optional.js diff --git a/changelog_unreleased/flow/11004.md b/changelog_unreleased/flow/11004.md new file mode 100644 index 000000000..eb9503928 --- /dev/null +++ b/changelog_unreleased/flow/11004.md @@ -0,0 +1,19 @@ +#### Fix parenthesis for optional function as return type (#11004 by @vjeux, @fisker) + + +```jsx +// Input +const fun = (a: number): (?(string => string)) => { + return a > 0 ? s => `${s}: ${a}` : null; +}; + +// Prettier stable +const fun = (a: number): ?(string) => string => { + return a > 0 ? (s) => `${s}: ${a}` : null; +}; + +// Prettier main +const fun = (a: number): (?(string) => string) => { + return a > 0 ? (s) => `${s}: ${a}` : null; +}; +``` diff --git a/src/language-js/parentheses/needs-parentheses.js b/src/language-js/parentheses/needs-parentheses.js index 503524e83..8e5031e8e 100644 --- a/src/language-js/parentheses/needs-parentheses.js +++ b/src/language-js/parentheses/needs-parentheses.js @@ -558,12 +558,31 @@ function needsParentheses(path, options) { ); case "InferTypeAnnotation": case "NullableTypeAnnotation": - return ( + if ( parent.type === "ArrayTypeAnnotation" || (key === "objectType" && (parent.type === "IndexedAccessType" || parent.type === "OptionalIndexedAccessType")) - ); + ) { + return true; + } + + // If the return type is a nullable arrow function, then we need a paren + // otherwise the inner => can be assumed to be for the outer one. + if ( + node.type === "NullableTypeAnnotation" && + path.match( + undefined, + (node, key) => + key === "typeAnnotation" && node.type === "TypeAnnotation", + (node, key) => + key === "returnType" && node.type === "ArrowFunctionExpression", + ) + ) { + return true; + } + + break; case "ComponentTypeAnnotation": case "FunctionTypeAnnotation": { diff --git a/tests/format/flow/parenthesis-return-type/__snapshots__/format.test.js.snap b/tests/format/flow/parenthesis-return-type/__snapshots__/format.test.js.snap new file mode 100644 index 000000000..d00bc43b2 --- /dev/null +++ b/tests/format/flow/parenthesis-return-type/__snapshots__/format.test.js.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`optional.js format 1`] = ` +====================================options===================================== +parsers: ["flow"] +printWidth: 80 + | printWidth +=====================================input====================================== +fun = (a: number): (?(string => string)) => { + return a > 0 ? s => \`\${s}: \${a}\` : null; +}; + +fun = (a: number): ?((string => string)) => { + return a > 0 ? s => \`\${s}: \${a}\` : null; +}; + +=====================================output===================================== +fun = (a: number): (?(string) => string) => { + return a > 0 ? (s) => \`\${s}: \${a}\` : null; +}; + +fun = (a: number): (?(string) => string) => { + return a > 0 ? (s) => \`\${s}: \${a}\` : null; +}; + +================================================================================ +`; diff --git a/tests/format/flow/parenthesis-return-type/format.test.js b/tests/format/flow/parenthesis-return-type/format.test.js new file mode 100644 index 000000000..55c339883 --- /dev/null +++ b/tests/format/flow/parenthesis-return-type/format.test.js @@ -0,0 +1 @@ +runFormatTest(import.meta, ["flow"]); diff --git a/tests/format/flow/parenthesis-return-type/optional.js b/tests/format/flow/parenthesis-return-type/optional.js new file mode 100644 index 000000000..0bb086ad9 --- /dev/null +++ b/tests/format/flow/parenthesis-return-type/optional.js @@ -0,0 +1,7 @@ +fun = (a: number): (?(string => string)) => { + return a > 0 ? s => `${s}: ${a}` : null; +}; + +fun = (a: number): ?((string => string)) => { + return a > 0 ? s => `${s}: ${a}` : null; +};