diff --git a/changelog_unreleased/typescript/18827-2.md b/changelog_unreleased/typescript/18827-2.md new file mode 100644 index 000000000..14e352f99 --- /dev/null +++ b/changelog_unreleased/typescript/18827-2.md @@ -0,0 +1,19 @@ +#### Don't break union type when it can fit (#18827 by @fisker) + + +```tsx +// Input +type Browser = "chromium" | "webkit" | "firefox" | "chromium-msedge" | "chromium-chrome"; + +// Prettier stable +type Browser = + | "chromium" + | "webkit" + | "firefox" + | "chromium-msedge" + | "chromium-chrome"; + +// Prettier main +type Browser = + "chromium" | "webkit" | "firefox" | "chromium-msedge" | "chromium-chrome"; +``` diff --git a/changelog_unreleased/typescript/18827.md b/changelog_unreleased/typescript/18827.md new file mode 100644 index 000000000..d1d232f92 --- /dev/null +++ b/changelog_unreleased/typescript/18827.md @@ -0,0 +1,22 @@ +#### Remove extra indention for union type in conditional type (#18827 by @fisker) + + +```tsx +// Input +type A = T extends "arrow" + ? ExcalidrawArrowElement["startBinding"] | ExcalidrawElbowArrowElement["startBinding"] + : never; + +// Prettier stable +type A = T extends "arrow" + ? + | ExcalidrawArrowElement["startBinding"] + | ExcalidrawElbowArrowElement["startBinding"] + : never; + +// Prettier main +type A = T extends "arrow" + ? | ExcalidrawArrowElement["startBinding"] + | ExcalidrawElbowArrowElement["startBinding"] + : never; +``` diff --git a/src/language-js/print/assignment.js b/src/language-js/print/assignment.js index 4be90cc6d..6a7c3ee82 100644 --- a/src/language-js/print/assignment.js +++ b/src/language-js/print/assignment.js @@ -28,6 +28,7 @@ import { } from "../utilities/node-types.js"; import { shouldInlineLogicalExpression } from "./binaryish.js"; import { printCallExpression } from "./call-expression.js"; +import { shouldHugUnionType } from "./union-type.js"; /** * @import AstPath from "../../common/ast-path.js" @@ -136,6 +137,7 @@ function chooseLayout(path, options, print, leftDoc, rightPropertyName) { if ( isHeadOfLongChain || + (isUnionType(rightNode) && !shouldHugUnionType(rightNode)) || hasLeadingOwnLineComment(options.originalText, rightNode) ) { return "break-after-operator"; diff --git a/src/language-js/print/flow.js b/src/language-js/print/flow.js index 4c07f8306..5dcc30895 100644 --- a/src/language-js/print/flow.js +++ b/src/language-js/print/flow.js @@ -53,7 +53,7 @@ import { printTypePredicate } from "./type-predicate.js"; import { printTypeQuery } from "./type-query.js"; import { printUnionType } from "./union-type.js"; -function printFlow(path, options, print) { +function printFlow(path, options, print, args) { const { node } = path; if (isFlowKeywordType(node)) { @@ -117,7 +117,7 @@ function printFlow(path, options, print) { case "IntersectionTypeAnnotation": return printIntersectionType(path, options, print); case "UnionTypeAnnotation": - return printUnionType(path, options, print); + return printUnionType(path, options, print, args); case "ConditionalTypeAnnotation": return printTernary(path, options, print); case "InferTypeAnnotation": diff --git a/src/language-js/print/typescript.js b/src/language-js/print/typescript.js index 4b542f685..61b3d6b8b 100644 --- a/src/language-js/print/typescript.js +++ b/src/language-js/print/typescript.js @@ -45,7 +45,7 @@ import { printTypePredicate } from "./type-predicate.js"; import { printTypeQuery } from "./type-query.js"; import { printUnionType } from "./union-type.js"; -function printTypescript(path, options, print) { +function printTypescript(path, options, print, args) { const { node } = path; // TypeScript nodes always starts with `TS` @@ -186,7 +186,7 @@ function printTypescript(path, options, print) { case "TSIntersectionType": return printIntersectionType(path, options, print); case "TSUnionType": - return printUnionType(path, options, print); + return printUnionType(path, options, print, args); case "TSFunctionType": case "TSCallSignatureDeclaration": case "TSConstructorType": diff --git a/src/language-js/print/union-type.js b/src/language-js/print/union-type.js index b33e7a385..10fcf4222 100644 --- a/src/language-js/print/union-type.js +++ b/src/language-js/print/union-type.js @@ -12,13 +12,13 @@ import { printCommentsSeparately, } from "../../main/comments/print.js"; import needsParentheses from "../parentheses/needs-parentheses.js"; -import { CommentCheckFlags, hasComment } from "../utilities/comments.js"; +import { hasComment } from "../utilities/comments.js"; import { createTypeCheckFunction } from "../utilities/create-type-check-function.js"; -import { hasLeadingOwnLineComment } from "../utilities/has-leading-own-line-comment.js"; +import { isFlowObjectTypePropertyAFunction } from "../utilities/is-flow-object-type-property-a-function.js"; import { isConditionalType, isTupleType, - isTypeAlias, + isTypeParameterInstantiation, } from "../utilities/node-types.js"; import { shouldUnionTypePrintOwnComments } from "../utilities/should-union-type-print-own-comments.js"; @@ -27,7 +27,7 @@ import { shouldUnionTypePrintOwnComments } from "../utilities/should-union-type- */ // `TSUnionType` and `UnionTypeAnnotation` -function printUnionType(path, options, print) { +function printUnionType(path, options, print, args) { const { node } = path; // single-line variation // A | B | C @@ -39,33 +39,6 @@ function printUnionType(path, options, print) { const { parent } = path; - // If there's a leading comment, the parent is doing the indentation - const shouldIndent = - parent.type !== "TypeParameterInstantiation" && - parent.type !== "TSTypeParameterInstantiation" && - parent.type !== "GenericTypeAnnotation" && - parent.type !== "TSTypeReference" && - parent.type !== "TSTypeAssertion" && - !isTupleType(parent) && - !( - parent.type === "FunctionTypeParam" && - !parent.name && - path.grandparent.this !== parent - ) && - !( - isConditionalType(parent) && - !options.experimentalTernaries && - hasLeadingOwnLineComment(options.originalText, node) - ) && - !( - (isTypeAlias(parent) || parent.type === "VariableDeclarator") && - hasLeadingOwnLineComment(options.originalText, node) - ) && - !( - isTypeAlias(parent) && - hasComment(parent.id, CommentCheckFlags.Trailing | CommentCheckFlags.Line) - ); - // { // a: string // } | null | void @@ -97,32 +70,65 @@ function printUnionType(path, options, print) { return [leading, join(" | ", printed), trailing]; } - const shouldAddStartLine = - shouldIndent && !hasLeadingOwnLineComment(options.originalText, node); - const mainParts = [ - ifBreak([shouldAddStartLine ? line : "", "| "]), - join([line, "| "], printed), + leading, + group([ifBreak("| "), join([line, "| "], printed)]), + trailing, ]; if (needsParentheses(path, options)) { - return [leading, group([indent(mainParts), softline]), trailing]; + return group([indent([softline, mainParts]), softline]); } - const parts = [leading, group(mainParts)]; - if (isTupleType(parent) && parent.elementTypes.length > 1) { return [ group([ - indent([ifBreak(["(", softline]), parts]), + indent([ifBreak(["(", softline]), mainParts]), softline, ifBreak(")"), ]), - trailing, ]; } - return [group(shouldIndent ? indent(parts) : parts), trailing]; + // Already indent in parent + if ( + args?.assignmentLayout === "break-after-operator" || + !shouldIndentUnionType(path) + ) { + return mainParts; + } + + return group(indent([softline, mainParts])); +} + +function shouldIndentUnionType(path) { + const { key, parent } = path; + if ( + (key === "typeAnnotation" && parent.type === "TSTypeAssertion") || + (key === "elementTypes" && isTupleType(parent)) || + ((key === "trueType" || key === "falseType") && + isConditionalType(parent)) || + (key === "params" && isTypeParameterInstantiation(parent)) + ) { + return false; + } + + if ( + path.match( + undefined, + (node, key) => + key === "typeAnnotation" && node.type === "FunctionTypeParam", + (node, key) => key === "params" && node.type === "FunctionTypeAnnotation", + (node, key) => + key === "value" && + node.type === "ObjectTypeProperty" && + isFlowObjectTypePropertyAFunction(node), + ) + ) { + return false; + } + + return true; } const isVoidType = createTypeCheckFunction([ diff --git a/src/language-js/utilities/node-types.js b/src/language-js/utilities/node-types.js index f949ce663..ea8db0af5 100644 --- a/src/language-js/utilities/node-types.js +++ b/src/language-js/utilities/node-types.js @@ -137,4 +137,9 @@ export const isArrayType = createTypeCheckFunction([ "ArrayTypeAnnotation", ]); +export const isTypeParameterInstantiation = createTypeCheckFunction([ + "TSTypeParameterInstantiation", + "TypeParameterInstantiation", +]); + export * from "./literal.js"; diff --git a/tests/config/format-test/failed-format-tests.js b/tests/config/format-test/failed-format-tests.js index b6a92f1e4..5801b0bc9 100644 --- a/tests/config/format-test/failed-format-tests.js +++ b/tests/config/format-test/failed-format-tests.js @@ -25,7 +25,6 @@ const unstableTests = new Map( "js/sequence-expression/parenthesized.js", "typescript/satisfies-operators/comments-unstable.ts", "jsx/comments/in-attributes.js", - "typescript/union/consistent-with-flow/single-type.ts", "typescript/import-type/long-module-name/long-module-name4.ts", // Unstable due to lack of indent information "js/multiparser-comments/comment-inside.js", diff --git a/tests/format/flow/as-satisfies-expression/__snapshots__/format.test.js.snap b/tests/format/flow/as-satisfies-expression/__snapshots__/format.test.js.snap index 868e6809f..d42db639e 100644 --- a/tests/format/flow/as-satisfies-expression/__snapshots__/format.test.js.snap +++ b/tests/format/flow/as-satisfies-expression/__snapshots__/format.test.js.snap @@ -87,8 +87,7 @@ const value1 = const value2 = thisIsAnIdentifier as thisIsAReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongInterface; const value3 = thisIsAReallyLongIdentifier as - | SomeInterface - | SomeOtherInterface; + SomeInterface | SomeOtherInterface; const value4 = thisIsAReallyLongIdentifier as { prop1: string, prop2: number, diff --git a/tests/format/flow/comments/normal-comments/__snapshots__/format.test.js.snap b/tests/format/flow/comments/normal-comments/__snapshots__/format.test.js.snap index 1efe2ade5..a8ec4adc1 100644 --- a/tests/format/flow/comments/normal-comments/__snapshots__/format.test.js.snap +++ b/tests/format/flow/comments/normal-comments/__snapshots__/format.test.js.snap @@ -13,7 +13,8 @@ type Foo = { =====================================output===================================== type Foo = { - bar: // test + bar: + // test | { loooooooooooooooooongPropName1: string } | { loooooooooooooooooongPropName2: string }, }; diff --git a/tests/format/flow/flow-repo/call_caching1/lib/__snapshots__/format.test.js.snap b/tests/format/flow/flow-repo/call_caching1/lib/__snapshots__/format.test.js.snap index 34f5880fd..3d09475e7 100644 --- a/tests/format/flow/flow-repo/call_caching1/lib/__snapshots__/format.test.js.snap +++ b/tests/format/flow/flow-repo/call_caching1/lib/__snapshots__/format.test.js.snap @@ -41,8 +41,7 @@ declare class Array { } type IteratorResult = - | { done: true, value?: Return } - | { done: false, value: Yield }; + { done: true, value?: Return } | { done: false, value: Yield }; interface $Iterator<+Yield, +Return, -Next> { @@iterator(): $Iterator; diff --git a/tests/format/flow/flow-repo/disjoint-union-perf/__snapshots__/format.test.js.snap b/tests/format/flow/flow-repo/disjoint-union-perf/__snapshots__/format.test.js.snap index 268b709a6..7b4aed3a0 100644 --- a/tests/format/flow/flow-repo/disjoint-union-perf/__snapshots__/format.test.js.snap +++ b/tests/format/flow/flow-repo/disjoint-union-perf/__snapshots__/format.test.js.snap @@ -1015,13 +1015,7 @@ export type BinaryOperator = | ".."; export type UnaryOperator = - | "-" - | "+" - | "!" - | "~" - | "typeof" - | "void" - | "delete"; + "-" | "+" | "!" | "~" | "typeof" | "void" | "delete"; export type AssignmentOperator = | "=" diff --git a/tests/format/flow/union/__snapshots__/format.test.js.snap b/tests/format/flow/union/__snapshots__/format.test.js.snap index 625b26924..5096f672d 100644 --- a/tests/format/flow/union/__snapshots__/format.test.js.snap +++ b/tests/format/flow/union/__snapshots__/format.test.js.snap @@ -12,7 +12,8 @@ const myValue = (callcallcallcallcallcall(87689769876876897698768768976987687689 =====================================output===================================== const myValue = (callcallcallcallcallcall( 87689769876876897698768768976987687689769876, -): // Comment +): + // Comment | one | two | thre diff --git a/tests/format/typescript/as/__snapshots__/format.test.js.snap b/tests/format/typescript/as/__snapshots__/format.test.js.snap index 049f165fd..31a946a87 100644 --- a/tests/format/typescript/as/__snapshots__/format.test.js.snap +++ b/tests/format/typescript/as/__snapshots__/format.test.js.snap @@ -104,8 +104,7 @@ const value1 = const value2 = thisIsAnIdentifier as thisIsAReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongInterface; const value3 = thisIsAReallyLongIdentifier as - | SomeInterface - | SomeOtherInterface; + SomeInterface | SomeOtherInterface; const value4 = thisIsAReallyLongIdentifier as { prop1: string; prop2: number; diff --git a/tests/format/typescript/as/break-after-keyword/__snapshots__/format.test.js.snap b/tests/format/typescript/as/break-after-keyword/__snapshots__/format.test.js.snap index 7c28db718..b1ee1d3ba 100644 --- a/tests/format/typescript/as/break-after-keyword/__snapshots__/format.test.js.snap +++ b/tests/format/typescript/as/break-after-keyword/__snapshots__/format.test.js.snap @@ -44,8 +44,7 @@ const firstItem_1 = ______________.items.find( // 79 width until \`as\` or \`satisfies\` keyword const firstItem2 = ______________.items.find((item) => item.type === "item") as - | string - | number; + string | number; // 80 width until \`as\` or \`satisfies\` keyword const firstItem_2 = ______________.items.find( (item) => item.type === "item", @@ -53,8 +52,7 @@ const firstItem_2 = ______________.items.find( // 79 width until \`as\` or \`satisfies\` keyword const firstItem3 = _____________.find((item) => item.type === "item") satisfies - | string - | number; + string | number; // 80 width until \`as\` or \`satisfies\` keyword const firstItem_3 = _____________.find( (item) => item.type === "item", diff --git a/tests/format/typescript/conditional-types/__snapshots__/format.test.js.snap b/tests/format/typescript/conditional-types/__snapshots__/format.test.js.snap index d2a00fb8b..b7a85e4c7 100644 --- a/tests/format/typescript/conditional-types/__snapshots__/format.test.js.snap +++ b/tests/format/typescript/conditional-types/__snapshots__/format.test.js.snap @@ -88,6 +88,11 @@ T = any instanceof B // Multiline comment ? B | C : D; +T = any instanceof B + ? D + // Comment + // Multiline comment + : B | C; type T = any extends B // Comment @@ -201,8 +206,8 @@ c */ type T = any extends B ? // Comment - // Multiline comment - B | C + // Multiline comment + B | C : D; T = any instanceof B ? @@ -210,11 +215,16 @@ T = // Multiline comment B | C : D; +T = + any instanceof B ? D + // Comment + // Multiline comment + : B | C; type T = any extends B ? // Comment - B | C + B | C : D; T = any instanceof B ? @@ -225,9 +235,9 @@ T = type T = any extends B ? /** - * Comment - */ - B | C + * Comment + */ + B | C : D; T = any instanceof B ? /** @@ -328,6 +338,11 @@ T = any instanceof B // Multiline comment ? B | C : D; +T = any instanceof B + ? D + // Comment + // Multiline comment + : B | C; type T = any extends B // Comment @@ -441,6 +456,12 @@ T = // Multiline comment B | C : D; +T = + any instanceof B + ? D + : // Comment + // Multiline comment + B | C; type T = any extends B ? // Comment diff --git a/tests/format/typescript/conditional-types/comments.ts b/tests/format/typescript/conditional-types/comments.ts index 9f322e103..1b6eabf59 100644 --- a/tests/format/typescript/conditional-types/comments.ts +++ b/tests/format/typescript/conditional-types/comments.ts @@ -80,6 +80,11 @@ T = any instanceof B // Multiline comment ? B | C : D; +T = any instanceof B + ? D + // Comment + // Multiline comment + : B | C; type T = any extends B // Comment diff --git a/tests/format/typescript/conformance/types/union/__snapshots__/format.test.js.snap b/tests/format/typescript/conformance/types/union/__snapshots__/format.test.js.snap index 458f9ca09..54152133a 100644 --- a/tests/format/typescript/conformance/types/union/__snapshots__/format.test.js.snap +++ b/tests/format/typescript/conformance/types/union/__snapshots__/format.test.js.snap @@ -101,45 +101,39 @@ unionOfDifferentReturnType1(true); // error in type of parameter unionOfDifferentReturnType1(); // error missing parameter var unionOfDifferentParameterTypes: - | { (a: number): number } - | { (a: string): Date }; + { (a: number): number } | { (a: string): Date }; unionOfDifferentParameterTypes(10); // error - no call signatures unionOfDifferentParameterTypes("hello"); // error - no call signatures unionOfDifferentParameterTypes(); // error - no call signatures var unionOfDifferentNumberOfSignatures: - | { (a: number): number } - | { (a: number): Date; (a: string): boolean }; + { (a: number): number } | { (a: number): Date; (a: string): boolean }; unionOfDifferentNumberOfSignatures(); // error - no call signatures unionOfDifferentNumberOfSignatures(10); // error - no call signatures unionOfDifferentNumberOfSignatures("hello"); // error - no call signatures var unionWithDifferentParameterCount: - | { (a: string): string } - | { (a: string, b: number): number }; + { (a: string): string } | { (a: string, b: number): number }; unionWithDifferentParameterCount(); // no call signature unionWithDifferentParameterCount("hello"); // no call signature unionWithDifferentParameterCount("hello", 10); // no call signature var unionWithOptionalParameter1: - | { (a: string, b?: number): string } - | { (a: string, b?: number): number }; + { (a: string, b?: number): string } | { (a: string, b?: number): number }; strOrNum = unionWithOptionalParameter1("hello"); strOrNum = unionWithOptionalParameter1("hello", 10); strOrNum = unionWithOptionalParameter1("hello", "hello"); // error in parameter type strOrNum = unionWithOptionalParameter1(); // error var unionWithOptionalParameter2: - | { (a: string, b?: number): string } - | { (a: string, b: number): number }; + { (a: string, b?: number): string } | { (a: string, b: number): number }; strOrNum = unionWithOptionalParameter2("hello"); // error no call signature strOrNum = unionWithOptionalParameter2("hello", 10); // error no call signature strOrNum = unionWithOptionalParameter2("hello", "hello"); // error no call signature strOrNum = unionWithOptionalParameter2(); // error no call signature var unionWithOptionalParameter3: - | { (a: string, b?: number): string } - | { (a: string): number }; + { (a: string, b?: number): string } | { (a: string): number }; strOrNum = unionWithOptionalParameter3("hello"); strOrNum = unionWithOptionalParameter3("hello", 10); // error no call signature strOrNum = unionWithOptionalParameter3("hello", "hello"); // error no call signature @@ -155,8 +149,7 @@ strOrNum = unionWithRestParameter1("hello", "hello"); // error in parameter type strOrNum = unionWithRestParameter1(); // error var unionWithRestParameter2: - | { (a: string, ...b: number[]): string } - | { (a: string, b: number): number }; + { (a: string, ...b: number[]): string } | { (a: string, b: number): number }; strOrNum = unionWithRestParameter2("hello"); // error no call signature strOrNum = unionWithRestParameter2("hello", 10); // error no call signature strOrNum = unionWithRestParameter2("hello", 10, 11); // error no call signature @@ -164,8 +157,7 @@ strOrNum = unionWithRestParameter2("hello", "hello"); // error no call signature strOrNum = unionWithRestParameter2(); // error no call signature var unionWithRestParameter3: - | { (a: string, ...b: number[]): string } - | { (a: string): number }; + { (a: string, ...b: number[]): string } | { (a: string): number }; strOrNum = unionWithRestParameter3("hello"); strOrNum = unionWithRestParameter3("hello", 10); // error no call signature strOrNum = unionWithRestParameter3("hello", 10, 11); // error no call signature @@ -173,8 +165,7 @@ strOrNum = unionWithRestParameter3("hello", "hello"); // error no call signature strOrNum = unionWithRestParameter3(); // error no call signature var unionWithRestParameter4: - | { (...a: string[]): string } - | { (a: string, b: string): number }; + { (...a: string[]): string } | { (a: string, b: string): number }; strOrNum = unionWithRestParameter4("hello"); // error supplied parameters do not match any call signature strOrNum = unionWithRestParameter4("hello", "world"); @@ -366,8 +357,7 @@ var strOrNum: string | number; // If each type in U has construct signatures and the sets of construct signatures are identical ignoring return types, // U has the same set of construct signatures, but with return types that are unions of the return types of the respective construct signatures from each type in U. var unionOfDifferentReturnType: - | { new (a: number): number } - | { new (a: number): Date }; + { new (a: number): number } | { new (a: number): Date }; numOrDate = new unionOfDifferentReturnType(10); strOrBoolean = new unionOfDifferentReturnType("hello"); // error new unionOfDifferentReturnType1(true); // error in type of parameter @@ -381,8 +371,7 @@ new unionOfDifferentReturnType1(true); // error in type of parameter new unionOfDifferentReturnType1(); // error missing parameter var unionOfDifferentParameterTypes: - | { new (a: number): number } - | { new (a: string): Date }; + { new (a: number): number } | { new (a: string): Date }; new unionOfDifferentParameterTypes(10); // error - no call signatures new unionOfDifferentParameterTypes("hello"); // error - no call signatures new unionOfDifferentParameterTypes(); // error - no call signatures @@ -395,8 +384,7 @@ new unionOfDifferentNumberOfSignatures(10); // error - no call signatures new unionOfDifferentNumberOfSignatures("hello"); // error - no call signatures var unionWithDifferentParameterCount: - | { new (a: string): string } - | { new (a: string, b: number): number }; + { new (a: string): string } | { new (a: string, b: number): number }; new unionWithDifferentParameterCount(); // no call signature new unionWithDifferentParameterCount("hello"); // no call signature new unionWithDifferentParameterCount("hello", 10); // no call signature @@ -418,8 +406,7 @@ strOrNum = new unionWithOptionalParameter2("hello", "hello"); // error no call s strOrNum = new unionWithOptionalParameter2(); // error no call signature var unionWithOptionalParameter3: - | { new (a: string, b?: number): string } - | { new (a: string): number }; + { new (a: string, b?: number): string } | { new (a: string): number }; strOrNum = new unionWithOptionalParameter3("hello"); // error no call signature strOrNum = new unionWithOptionalParameter3("hello", 10); // error no call signature strOrNum = new unionWithOptionalParameter3("hello", "hello"); // error no call signature @@ -444,8 +431,7 @@ strOrNum = new unionWithRestParameter2("hello", "hello"); // error no call signa strOrNum = new unionWithRestParameter2(); // error no call signature var unionWithRestParameter3: - | { new (a: string, ...b: number[]): string } - | { new (a: string): number }; + { new (a: string, ...b: number[]): string } | { new (a: string): number }; strOrNum = new unionWithRestParameter3("hello"); // error no call signature strOrNum = new unionWithRestParameter3("hello", 10); // error no call signature strOrNum = new unionWithRestParameter3("hello", 10, 11); // error no call signature @@ -610,22 +596,19 @@ numOrDate = unionOfDifferentReturnType["hello"]; // number | Date numOrDate = unionOfDifferentReturnType[10]; // number | Date var unionOfTypesWithAndWithoutStringSignature: - | { [a: string]: number } - | boolean; + { [a: string]: number } | boolean; anyVar = unionOfTypesWithAndWithoutStringSignature["hello"]; // any anyVar = unionOfTypesWithAndWithoutStringSignature[10]; // any // If each type in U has a numeric index signature, // U has a numeric index signature of a union type of the types of the numeric index signatures from each type in U. var unionOfDifferentReturnType1: - | { [a: number]: number } - | { [a: number]: Date }; + { [a: number]: number } | { [a: number]: Date }; numOrDate = unionOfDifferentReturnType1["hello"]; // any numOrDate = unionOfDifferentReturnType1[10]; // number | Date var unionOfTypesWithAndWithoutStringSignature1: - | { [a: number]: number } - | boolean; + { [a: number]: number } | boolean; anyVar = unionOfTypesWithAndWithoutStringSignature1["hello"]; // any anyVar = unionOfTypesWithAndWithoutStringSignature1[10]; // any diff --git a/tests/format/typescript/prettier-ignore/__snapshots__/format.test.js.snap b/tests/format/typescript/prettier-ignore/__snapshots__/format.test.js.snap index ab98ef82b..3e6eeb44e 100644 --- a/tests/format/typescript/prettier-ignore/__snapshots__/format.test.js.snap +++ b/tests/format/typescript/prettier-ignore/__snapshots__/format.test.js.snap @@ -131,7 +131,8 @@ type c = { }; type d = { - [A in B]: // prettier-ignore + [A in B]: + // prettier-ignore C | D; }; @@ -150,7 +151,8 @@ type f = { }; type g = { - [A in B]: /* prettier-ignore */ + [A in B]: + /* prettier-ignore */ C | D; }; diff --git a/tests/format/typescript/property-signature/consistent-with-flow/__snapshots__/format.test.js.snap b/tests/format/typescript/property-signature/consistent-with-flow/__snapshots__/format.test.js.snap index 201889216..974ff037a 100644 --- a/tests/format/typescript/property-signature/consistent-with-flow/__snapshots__/format.test.js.snap +++ b/tests/format/typescript/property-signature/consistent-with-flow/__snapshots__/format.test.js.snap @@ -66,7 +66,8 @@ export interface DirectiveArgumentNode extends ArrayExpression { =====================================output===================================== export interface DirectiveArgumentNode extends ArrayExpression { - elements: // dir, exp, arg, modifiers + elements: + // dir, exp, arg, modifiers | [string] | [string, ExpressionNode] | [string, ExpressionNode, ExpressionNode] diff --git a/tests/format/typescript/type-parameters-arguments/__snapshots__/format.test.js.snap b/tests/format/typescript/type-parameters-arguments/__snapshots__/format.test.js.snap index 1cfd1af55..3a6bfabfd 100644 --- a/tests/format/typescript/type-parameters-arguments/__snapshots__/format.test.js.snap +++ b/tests/format/typescript/type-parameters-arguments/__snapshots__/format.test.js.snap @@ -62,7 +62,8 @@ type A< type BufferStreamOrVoid< C extends undefined | Buffer | Stream | boolean, P extends undefined | Buffer, - R extends Buffer | Stream | void = // Inline comment about void. + R extends + Buffer | Stream | void = // Inline comment about void. // Above line comment about exclue. Exclude extends never ? void @@ -556,13 +557,11 @@ export type OuterType32< export type OuterType4< LongerLongerLongerLongerInnerType extends - | LongerLongerLongerLongerLongerLo - | ngerLongerLongerOtherType, + LongerLongerLongerLongerLongerLo | ngerLongerLongerOtherType, > = { a: 1 }; export type OuterType42< LongerLongerLongerLongerInnerType = - | LongerLongerLongerLongerLongerLo - | ngerLongerLongerOtherType, + LongerLongerLongerLongerLongerLo | ngerLongerLongerOtherType, > = { a: 1 }; ================================================================================ diff --git a/tests/format/typescript/union/10599.ts b/tests/format/typescript/union/10599.ts new file mode 100644 index 000000000..29671e899 --- /dev/null +++ b/tests/format/typescript/union/10599.ts @@ -0,0 +1,16 @@ +export interface ProductStatus { + type: + // eslint-disable-next-line sonar/max-union-size + | 'NotDeployed' + | 'InDeployment' + | 'Running' + | 'DeploymentFailure' + | 'RunningAbnormal' + | 'Deleting' + | 'DeleteFailure' + | 'DeploymentSucceed' + | 'SystemError' + | 'Upgrading'; + icon: string; + text: string; +} diff --git a/tests/format/typescript/union/5849.ts b/tests/format/typescript/union/5849.ts new file mode 100644 index 000000000..8df04ad40 --- /dev/null +++ b/tests/format/typescript/union/5849.ts @@ -0,0 +1,32 @@ +export type TransformedSource = { + code: string; + map?: + // copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/363cdf403a74e0372e87bbcd15eb1668f4c5230b/types/babel__core/index.d.ts#L371-L379 + | { + version: number; + sources: string[]; + names: string[]; + sourceRoot?: string; + sourcesContent?: string[]; + mappings: string; + file: string; + } + | string + | null; +}; + +export type TransformedSource2 = { + code: string, + map?: // copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/363cdf403a74e0372e87bbcd15eb1668f4c5230b/types/babel__core/index.d.ts#L371-L379 + | { + version: number, + sources: string[], + names: string[], + sourceRoot?: string, + sourcesContent?: string[], + mappings: string, + file: string + } + | string + | null +}; diff --git a/tests/format/typescript/union/7725.ts b/tests/format/typescript/union/7725.ts new file mode 100644 index 000000000..de4032eac --- /dev/null +++ b/tests/format/typescript/union/7725.ts @@ -0,0 +1,16 @@ +type T = { + prop: + // comment + | T1 + // comment + | T2 + // comment +} + +type T2 = (arg: + // comment + | T1 + // comment + | T2 + // comment +) => void diff --git a/tests/format/typescript/union/__snapshots__/format.test.js.snap b/tests/format/typescript/union/__snapshots__/format.test.js.snap index c1ff21e0c..f4e6a8989 100644 --- a/tests/format/typescript/union/__snapshots__/format.test.js.snap +++ b/tests/format/typescript/union/__snapshots__/format.test.js.snap @@ -1,5 +1,168 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing +exports[`5849.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] + printWidth: 80 (default) | +=====================================input====================================== +export type TransformedSource = { + code: string; + map?: + // copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/363cdf403a74e0372e87bbcd15eb1668f4c5230b/types/babel__core/index.d.ts#L371-L379 + | { + version: number; + sources: string[]; + names: string[]; + sourceRoot?: string; + sourcesContent?: string[]; + mappings: string; + file: string; + } + | string + | null; +}; + +export type TransformedSource2 = { + code: string, + map?: // copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/363cdf403a74e0372e87bbcd15eb1668f4c5230b/types/babel__core/index.d.ts#L371-L379 + | { + version: number, + sources: string[], + names: string[], + sourceRoot?: string, + sourcesContent?: string[], + mappings: string, + file: string + } + | string + | null +}; + +=====================================output===================================== +export type TransformedSource = { + code: string; + map?: + // copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/363cdf403a74e0372e87bbcd15eb1668f4c5230b/types/babel__core/index.d.ts#L371-L379 + | { + version: number; + sources: string[]; + names: string[]; + sourceRoot?: string; + sourcesContent?: string[]; + mappings: string; + file: string; + } + | string + | null; +}; + +export type TransformedSource2 = { + code: string; + map?: + // copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/363cdf403a74e0372e87bbcd15eb1668f4c5230b/types/babel__core/index.d.ts#L371-L379 + | { + version: number; + sources: string[]; + names: string[]; + sourceRoot?: string; + sourcesContent?: string[]; + mappings: string; + file: string; + } + | string + | null; +}; + +================================================================================ +`; + +exports[`7725.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] + printWidth: 80 (default) | +=====================================input====================================== +type T = { + prop: + // comment + | T1 + // comment + | T2 + // comment +} + +type T2 = (arg: + // comment + | T1 + // comment + | T2 + // comment +) => void + +=====================================output===================================== +type T = { + prop: + // comment + | T1 + // comment + | T2; + // comment +}; + +type T2 = ( + arg: + // comment + | T1 + // comment + | T2, + // comment +) => void; + +================================================================================ +`; + +exports[`10599.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] + printWidth: 80 (default) | +=====================================input====================================== +export interface ProductStatus { + type: + // eslint-disable-next-line sonar/max-union-size + | 'NotDeployed' + | 'InDeployment' + | 'Running' + | 'DeploymentFailure' + | 'RunningAbnormal' + | 'Deleting' + | 'DeleteFailure' + | 'DeploymentSucceed' + | 'SystemError' + | 'Upgrading'; + icon: string; + text: string; +} + +=====================================output===================================== +export interface ProductStatus { + type: + // eslint-disable-next-line sonar/max-union-size + | "NotDeployed" + | "InDeployment" + | "Running" + | "DeploymentFailure" + | "RunningAbnormal" + | "Deleting" + | "DeleteFailure" + | "DeploymentSucceed" + | "SystemError" + | "Upgrading"; + icon: string; + text: string; +} + +================================================================================ +`; + exports[`inlining.ts format 1`] = ` ====================================options===================================== parsers: ["typescript"] @@ -149,6 +312,32 @@ type T8 = number | ((arg: any) => void); ================================================================================ `; +exports[`trailing-comment.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] + printWidth: 80 (default) | +=====================================input====================================== +export const CONDITIONAL_AXIS_PROP_INDEX: Record< + ConditionalAxisProp, + { + part: keyof AxisEncode; + vgProp: VgEncodeChannel; + } | null // null if we need to convert condition to signal +> = { +} + +=====================================output===================================== +export const CONDITIONAL_AXIS_PROP_INDEX: Record< + ConditionalAxisProp, + { + part: keyof AxisEncode; + vgProp: VgEncodeChannel; + } | null // null if we need to convert condition to signal +> = {}; + +================================================================================ +`; + exports[`union-parens.ts format 1`] = ` ====================================options===================================== parsers: ["typescript"] @@ -306,8 +495,7 @@ type State = { ); const foo1 = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as ( - | string - | undefined + string | undefined )[]; const foo2: ( diff --git a/tests/format/typescript/union/comments/__snapshots__/format.test.js.snap b/tests/format/typescript/union/comments/__snapshots__/format.test.js.snap index 15199f5c9..e70525ece 100644 --- a/tests/format/typescript/union/comments/__snapshots__/format.test.js.snap +++ b/tests/format/typescript/union/comments/__snapshots__/format.test.js.snap @@ -50,7 +50,8 @@ type A3 = /* block comment =====================================output===================================== export interface DirectiveArgumentNode1 extends ArrayExpression { - elements: // dir, exp, arg, modifiers + elements: + // dir, exp, arg, modifiers | [string] | [string, ExpressionNode] | [string, ExpressionNode, ExpressionNode] @@ -58,7 +59,8 @@ export interface DirectiveArgumentNode1 extends ArrayExpression { } export class DirectiveArgumentNode12 extends ArrayExpression { - elements: // dir, exp, arg, modifiers + elements: + // dir, exp, arg, modifiers | [string] | [string, ExpressionNode] | [string, ExpressionNode, ExpressionNode] @@ -71,7 +73,8 @@ type A = // dir, exp, arg, modifiers | [string, ExpressionNode, ExpressionNode] | [string, ExpressionNode, ExpressionNode, ObjectExpression]; -const elements: // dir, exp, arg, modifiers +const elements: + // dir, exp, arg, modifiers | [string] | [string, ExpressionNode] | [string, ExpressionNode, ExpressionNode] @@ -214,3 +217,24 @@ type A4 = ================================================================================ `; + +exports[`mutiple.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript", "flow"] + printWidth: 80 (default) | +=====================================input====================================== +type _Test = + // forcing the test onto a new line so it isn't covered by the expect error + // If there are any enum members that don't have a corresponding TSESTree.Node, then this line will error with "Type 'string | number | symbol' is not assignable to type 'string'." + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + TakesString | void; + +=====================================output===================================== +type _Test = + // forcing the test onto a new line so it isn't covered by the expect error + // If there are any enum members that don't have a corresponding TSESTree.Node, then this line will error with "Type 'string | number | symbol' is not assignable to type 'string'." + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + TakesString | void; + +================================================================================ +`; diff --git a/tests/format/typescript/union/comments/mutiple.ts b/tests/format/typescript/union/comments/mutiple.ts new file mode 100644 index 000000000..39bd848ab --- /dev/null +++ b/tests/format/typescript/union/comments/mutiple.ts @@ -0,0 +1,5 @@ +type _Test = + // forcing the test onto a new line so it isn't covered by the expect error + // If there are any enum members that don't have a corresponding TSESTree.Node, then this line will error with "Type 'string | number | symbol' is not assignable to type 'string'." + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + TakesString | void; diff --git a/tests/format/typescript/union/consistent-with-flow/18647.ts b/tests/format/typescript/union/consistent-with-flow/18647.ts new file mode 100644 index 000000000..2a2660d99 --- /dev/null +++ b/tests/format/typescript/union/consistent-with-flow/18647.ts @@ -0,0 +1,18 @@ +type T = any extends B + /** + * Comment + */ + ? B | C + : D; +type T2 = any extends B + ? B | C + /** + * Comment + */ + : D; +T = any instanceof B + /** + * Comment + */ + ? B | C + : D; diff --git a/tests/format/typescript/union/consistent-with-flow/18819.ts b/tests/format/typescript/union/consistent-with-flow/18819.ts new file mode 100644 index 000000000..d0344c080 --- /dev/null +++ b/tests/format/typescript/union/consistent-with-flow/18819.ts @@ -0,0 +1,3 @@ +functionArg = a as + // comment + TSESTree.ArrowFunctionExpression | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression | undefined; diff --git a/tests/format/typescript/union/consistent-with-flow/__snapshots__/format.test.js.snap b/tests/format/typescript/union/consistent-with-flow/__snapshots__/format.test.js.snap index cbac37f2f..4d5c070c5 100644 --- a/tests/format/typescript/union/consistent-with-flow/__snapshots__/format.test.js.snap +++ b/tests/format/typescript/union/consistent-with-flow/__snapshots__/format.test.js.snap @@ -60,42 +60,96 @@ type ClassLike________80 = =====================================output===================================== export type ButtonColor = - | "primary" - | "danger" - | "warning" - | "muted" - | "success"; + "primary" | "danger" | "warning" | "muted" | "success"; export type Button__80 = "primary" | "danger" | "warning" | "muted" | "success"; export type SupportOptionType = - | "int" - | "string" - | "boolean" - | "choice" - | "path"; + "int" | "string" | "boolean" | "choice" | "path"; export type SupportOption_80 = "int" | "string" | "boolean" | "choice" | "path"; export type RenderContextType = - | "data" - | "header" - | "footer" - | "columnsSelector"; + "data" | "header" | "footer" | "columnsSelector"; export type RenderContext_80 = "data" | "header" | "footer" | "columnsSelector"; export type PropertyNameNonComputed = - | Identifier - | NumberLiteral - | StringLiteral; + Identifier | NumberLiteral | StringLiteral; export type PropertyNameNon_____80 = Identifier | NumberLiteral | StringLiteral; type ClassLikeDeclaration = - | TSESTree.ClassDeclaration - | TSESTree.ClassExpression; + TSESTree.ClassDeclaration | TSESTree.ClassExpression; type ClassLike________80 = TSESTree.ClassDeclaration | TSESTree.ClassExpression; ================================================================================ `; +exports[`18647.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript", "flow"] + printWidth: 80 (default) | +=====================================input====================================== +type T = any extends B + /** + * Comment + */ + ? B | C + : D; +type T2 = any extends B + ? B | C + /** + * Comment + */ + : D; +T = any instanceof B + /** + * Comment + */ + ? B | C + : D; + +=====================================output===================================== +type T = any extends B + ? /** + * Comment + */ + B | C + : D; +type T2 = any extends B + ? B | C + : /** + * Comment + */ + D; +T = + any instanceof B + ? /** + * Comment + */ + B | C + : D; + +================================================================================ +`; + +exports[`18819.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript", "flow"] + printWidth: 80 (default) | +=====================================input====================================== +functionArg = a as + // comment + TSESTree.ArrowFunctionExpression | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression | undefined; + +=====================================output===================================== +functionArg = a as + // comment + | TSESTree.ArrowFunctionExpression + | TSESTree.ArrowFunctionExpression + | TSESTree.FunctionExpression + | undefined; + +================================================================================ +`; + exports[`comment.ts format 1`] = ` ====================================options===================================== parsers: ["typescript", "flow"] @@ -183,6 +237,26 @@ type B3 = a | /* 1 */ /* 2 */ b; ================================================================================ `; +exports[`conditional.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript", "flow"] + printWidth: 80 (default) | +=====================================input====================================== +// https://github.com/excalidraw/excalidraw/blob/f12ae80ba1e1364952c6c6c440ac4212acd06eab/packages/excalidraw/tests/helpers/api.ts#L208C1-L210C15 +type A = T extends "arrow" + ? ExcalidrawArrowElement["startBinding"] | ExcalidrawElbowArrowElement["startBinding"] + : never; + +=====================================output===================================== +// https://github.com/excalidraw/excalidraw/blob/f12ae80ba1e1364952c6c6c440ac4212acd06eab/packages/excalidraw/tests/helpers/api.ts#L208C1-L210C15 +type A = T extends "arrow" + ? | ExcalidrawArrowElement["startBinding"] + | ExcalidrawElbowArrowElement["startBinding"] + : never; + +================================================================================ +`; + exports[`prettier-ignore.ts format 1`] = ` ====================================options===================================== parsers: ["typescript", "flow"] @@ -358,8 +432,8 @@ type A5 = | ({ key: string } | { key: string } | { key: string } | { key: string }) | { key: string } | { key: string }; -type A6 = /*1*/ - | A +type A6 = + /*1*/ | A // A comment to force break | B; diff --git a/tests/format/typescript/union/consistent-with-flow/conditional.ts b/tests/format/typescript/union/consistent-with-flow/conditional.ts new file mode 100644 index 000000000..20555f407 --- /dev/null +++ b/tests/format/typescript/union/consistent-with-flow/conditional.ts @@ -0,0 +1,4 @@ +// https://github.com/excalidraw/excalidraw/blob/f12ae80ba1e1364952c6c6c440ac4212acd06eab/packages/excalidraw/tests/helpers/api.ts#L208C1-L210C15 +type A = T extends "arrow" + ? ExcalidrawArrowElement["startBinding"] | ExcalidrawElbowArrowElement["startBinding"] + : never; diff --git a/tests/format/typescript/union/trailing-comment.ts b/tests/format/typescript/union/trailing-comment.ts new file mode 100644 index 000000000..c4b215a9b --- /dev/null +++ b/tests/format/typescript/union/trailing-comment.ts @@ -0,0 +1,8 @@ +export const CONDITIONAL_AXIS_PROP_INDEX: Record< + ConditionalAxisProp, + { + part: keyof AxisEncode; + vgProp: VgEncodeChannel; + } | null // null if we need to convert condition to signal +> = { +}