Fix missing parentheses in ConditionalTypeAnnotation (#17196)
This commit is contained in:
1 parent
fa95c97eb3
commit
a2e560e951
9 files changed
+83
-38
No files matched your search
@@ -0,0 +1,16 @@
|
||||
#### Fix missing parentheses in `ConditionalTypeAnnotation` (#17196 by @fisker)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
// Input
|
||||
type T<U> = 'a' | ('b' extends U ? 'c' : empty);
|
||||
type T<U> = 'a' & ('b' extends U ? 'c' : empty);
|
||||
|
||||
// Prettier stable
|
||||
type T<U> = "a" | "b" extends U ? "c" : empty;
|
||||
type T<U> = "a" & "b" extends U ? "c" : empty;
|
||||
|
||||
// Prettier main
|
||||
type T<U> = "a" | ("b" extends U ? "c" : empty);
|
||||
type T<U> = "a" & ("b" extends U ? "c" : empty);
|
||||
```
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
getFunctionParameters,
|
||||
isCallExpression,
|
||||
isCallLikeExpression,
|
||||
isConditionalType,
|
||||
isIntersectionType,
|
||||
isLineComment,
|
||||
isMemberExpression,
|
||||
@@ -360,8 +361,7 @@ function handleNestedConditionalExpressionComments({
|
||||
|
||||
const enclosingIsCond =
|
||||
enclosingNode?.type === "ConditionalExpression" ||
|
||||
enclosingNode?.type === "ConditionalTypeAnnotation" ||
|
||||
enclosingNode?.type === "TSConditionalType";
|
||||
isConditionalType(enclosingNode);
|
||||
|
||||
if (!enclosingIsCond) {
|
||||
return false;
|
||||
@@ -369,8 +369,7 @@ function handleNestedConditionalExpressionComments({
|
||||
|
||||
const followingIsCond =
|
||||
followingNode?.type === "ConditionalExpression" ||
|
||||
followingNode?.type === "ConditionalTypeAnnotation" ||
|
||||
followingNode?.type === "TSConditionalType";
|
||||
isConditionalType(followingNode);
|
||||
|
||||
if (followingIsCond) {
|
||||
addDanglingComment(enclosingNode, comment);
|
||||
@@ -394,8 +393,7 @@ function handleConditionalExpressionComments({
|
||||
if (
|
||||
(!precedingNode || !isSameLineAsPrecedingNode) &&
|
||||
(enclosingNode?.type === "ConditionalExpression" ||
|
||||
enclosingNode?.type === "ConditionalTypeAnnotation" ||
|
||||
enclosingNode?.type === "TSConditionalType") &&
|
||||
isConditionalType(enclosingNode)) &&
|
||||
followingNode
|
||||
) {
|
||||
if (
|
||||
|
||||
@@ -10,10 +10,13 @@ import {
|
||||
isBinaryCastExpression,
|
||||
isBitwiseOperator,
|
||||
isCallExpression,
|
||||
isConditionalType,
|
||||
isIntersectionType,
|
||||
isMemberExpression,
|
||||
isNullishCoalescing,
|
||||
isObjectOrRecordExpression,
|
||||
isObjectProperty,
|
||||
isUnionType,
|
||||
shouldFlatten,
|
||||
startsWithNoLookaheadToken,
|
||||
} from "./utils/index.js";
|
||||
@@ -531,11 +534,20 @@ function needsParens(path, options) {
|
||||
// fallthrough
|
||||
case "TSConditionalType":
|
||||
case "TSConstructorType":
|
||||
if (key === "extendsType" && parent.type === "TSConditionalType") {
|
||||
if (node.type === "TSConditionalType") {
|
||||
return true;
|
||||
}
|
||||
case "ConditionalTypeAnnotation":
|
||||
if (
|
||||
key === "extendsType" &&
|
||||
isConditionalType(node) &&
|
||||
parent.type === node.type
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key === "checkType" && isConditionalType(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key === "extendsType" && parent.type === "TSConditionalType") {
|
||||
let { typeAnnotation } = node.returnType || node.typeAnnotation;
|
||||
|
||||
if (
|
||||
@@ -553,15 +565,11 @@ function needsParens(path, options) {
|
||||
}
|
||||
}
|
||||
|
||||
if (key === "checkType" && parent.type === "TSConditionalType") {
|
||||
return true;
|
||||
}
|
||||
// fallthrough
|
||||
case "TSUnionType":
|
||||
case "TSIntersectionType":
|
||||
if (
|
||||
(parent.type === "TSUnionType" ||
|
||||
parent.type === "TSIntersectionType") &&
|
||||
(isUnionType(parent) || isIntersectionType(parent)) &&
|
||||
parent.types.length > 1 &&
|
||||
(!node.types || node.types.length > 1)
|
||||
) {
|
||||
@@ -712,19 +720,6 @@ function needsParens(path, options) {
|
||||
);
|
||||
}
|
||||
|
||||
case "ConditionalTypeAnnotation":
|
||||
if (
|
||||
key === "extendsType" &&
|
||||
parent.type === "ConditionalTypeAnnotation" &&
|
||||
node.type === "ConditionalTypeAnnotation"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key === "checkType" && parent.type === "ConditionalTypeAnnotation") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// fallthrough
|
||||
case "OptionalIndexedAccessType":
|
||||
return key === "objectType" && parent.type === "IndexedAccessType";
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
hasComment,
|
||||
isBinaryCastExpression,
|
||||
isCallExpression,
|
||||
isConditionalType,
|
||||
isJsxElement,
|
||||
isLoneShortArgument,
|
||||
isMemberExpression,
|
||||
@@ -153,9 +154,7 @@ function printTernary(path, options, print, args) {
|
||||
|
||||
const { node } = path;
|
||||
const isConditionalExpression = node.type === "ConditionalExpression";
|
||||
const isTSConditional =
|
||||
node.type === "TSConditionalType" ||
|
||||
node.type === "ConditionalTypeAnnotation"; // For Flow.
|
||||
const isTSConditional = isConditionalType(node);
|
||||
const consequentNodePropertyName = isConditionalExpression
|
||||
? "consequent"
|
||||
: "trueType";
|
||||
@@ -322,8 +321,7 @@ function printTernary(path, options, print, args) {
|
||||
" ",
|
||||
"extends",
|
||||
" ",
|
||||
node.extendsType.type === "TSConditionalType" ||
|
||||
node.extendsType.type === "ConditionalTypeAnnotation" ||
|
||||
isConditionalType(node.extendsType) ||
|
||||
node.extendsType.type === "TSMappedType"
|
||||
? print("extendsType")
|
||||
: group(wrapInParens(print("extendsType"))),
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
createTypeCheckFunction,
|
||||
hasComment,
|
||||
hasLeadingOwnLineComment,
|
||||
isConditionalType,
|
||||
isFlowObjectTypePropertyAFunction,
|
||||
isObjectType,
|
||||
isSimpleType,
|
||||
@@ -174,9 +175,7 @@ function printUnionType(path, options, print) {
|
||||
// If there's a leading comment, the parent is doing the indentation
|
||||
const shouldIndent =
|
||||
parent.type !== "TypeParameterInstantiation" &&
|
||||
(parent.type !== "TSConditionalType" || !options.experimentalTernaries) &&
|
||||
(parent.type !== "ConditionalTypeAnnotation" ||
|
||||
!options.experimentalTernaries) &&
|
||||
(!isConditionalType(parent) || !options.experimentalTernaries) &&
|
||||
parent.type !== "TSTypeParameterInstantiation" &&
|
||||
parent.type !== "GenericTypeAnnotation" &&
|
||||
parent.type !== "TSTypeReference" &&
|
||||
|
||||
@@ -1074,13 +1074,18 @@ const isBinaryCastExpression = createTypeCheckFunction([
|
||||
]);
|
||||
|
||||
const isUnionType = createTypeCheckFunction([
|
||||
"UnionTypeAnnotation",
|
||||
"TSUnionType",
|
||||
"UnionTypeAnnotation",
|
||||
]);
|
||||
|
||||
const isIntersectionType = createTypeCheckFunction([
|
||||
"IntersectionTypeAnnotation",
|
||||
"TSIntersectionType",
|
||||
"IntersectionTypeAnnotation",
|
||||
]);
|
||||
|
||||
const isConditionalType = createTypeCheckFunction([
|
||||
"TSConditionalType",
|
||||
"ConditionalTypeAnnotation",
|
||||
]);
|
||||
|
||||
export {
|
||||
@@ -1106,6 +1111,7 @@ export {
|
||||
isBitwiseOperator,
|
||||
isCallExpression,
|
||||
isCallLikeExpression,
|
||||
isConditionalType,
|
||||
isExportDeclaration,
|
||||
isFlowObjectTypePropertyAFunction,
|
||||
isFunctionCompositionArgs,
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`union.js [babel-flow] format 1`] = `
|
||||
"Unexpected token, expected ")" (1:24)
|
||||
> 1 | type T<U> = 'a' | ('b' extends U ? 'c' : empty);
|
||||
| ^
|
||||
2 | type T<U> = 'a' & ('b' extends U ? 'c' : empty);
|
||||
3 |
|
||||
Cause: Unexpected token, expected ")" (1:23)"
|
||||
`;
|
||||
|
||||
exports[`union.js format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["flow", "typescript"]
|
||||
printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
type T<U> = 'a' | ('b' extends U ? 'c' : empty);
|
||||
type T<U> = 'a' & ('b' extends U ? 'c' : empty);
|
||||
|
||||
=====================================output=====================================
|
||||
type T<U> = "a" | ("b" extends U ? "c" : empty);
|
||||
type T<U> = "a" & ("b" extends U ? "c" : empty);
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
@@ -0,0 +1,5 @@
|
||||
runFormatTest(import.meta, ["flow", "typescript"], {
|
||||
errors: {
|
||||
"babel-flow": true,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
type T<U> = 'a' | ('b' extends U ? 'c' : empty);
|
||||
type T<U> = 'a' & ('b' extends U ? 'c' : empty);
|
||||
Reference in new issue
Block a user