diff --git a/.changeset/honest-eagles-learn.md b/.changeset/honest-eagles-learn.md new file mode 100644 index 000000000000..b5d923861936 --- /dev/null +++ b/.changeset/honest-eagles-learn.md @@ -0,0 +1,22 @@ +--- +"@biomejs/biome": patch +--- + +Fixed [#7806](https://github.com/biomejs/biome/issues/7806): Prefer breaking after the assignment operator for conditional types with generic parameters to match Prettier. + +```diff +-type True = unknown extends Type< +- "many", +- "generic", +- "parameters", +- "one", +- "two", +- "three" +-> +- ? true +- : false; ++type True = ++ unknown extends Type<"many", "generic", "parameters", "one", "two", "three"> ++ ? true ++ : false; +``` diff --git a/crates/biome_js_formatter/src/utils/assignment_like.rs b/crates/biome_js_formatter/src/utils/assignment_like.rs index 460d01f4fd54..1605ef1668c6 100644 --- a/crates/biome_js_formatter/src/utils/assignment_like.rs +++ b/crates/biome_js_formatter/src/utils/assignment_like.rs @@ -16,9 +16,9 @@ use biome_js_syntax::{ JsInitializerClause, JsLiteralMemberName, JsObjectAssignmentPattern, JsObjectAssignmentPatternProperty, JsObjectBindingPattern, JsPropertyClassMember, JsPropertyClassMemberFields, JsPropertyObjectMember, JsSyntaxKind, JsVariableDeclarator, - TsInitializedPropertySignatureClassMember, TsInitializedPropertySignatureClassMemberFields, - TsPropertySignatureClassMember, TsPropertySignatureClassMemberFields, TsTypeAliasDeclaration, - TsTypeArguments, TsUnionType, + TsConditionalType, TsInitializedPropertySignatureClassMember, + TsInitializedPropertySignatureClassMemberFields, TsPropertySignatureClassMember, + TsPropertySignatureClassMemberFields, TsTypeAliasDeclaration, TsTypeArguments, TsUnionType, }; use biome_js_syntax::{AnyJsLiteralExpression, JsUnaryExpression}; use biome_rowan::{AstNode, SyntaxNodeOptionExt, SyntaxResult, declare_node_union}; @@ -931,6 +931,10 @@ impl AnyJsAssignmentLike { } has_leading_comments } + RightAssignmentLike::AnyTsType(AnyTsType::TsConditionalType(conditional_type)) => { + comments.has_leading_own_line_comment(conditional_type.syntax()) + || should_break_before_conditional_type(conditional_type)? + } right => comments.has_leading_own_line_comment(right.syntax()), }; @@ -938,6 +942,23 @@ impl AnyJsAssignmentLike { } } +fn is_generic(ty: &AnyTsType) -> bool { + match ty { + AnyTsType::TsReferenceType(reference) => reference.type_arguments().is_some(), + AnyTsType::TsFunctionType(function) => function.type_parameters().is_some(), + _ => false, + } +} + +fn should_break_before_conditional_type( + conditional_type: &TsConditionalType, +) -> SyntaxResult { + Ok( + is_generic(&conditional_type.check_type()?) + || is_generic(&conditional_type.extends_type()?), + ) +} + /// Checks if the function is entitled to be printed with layout [AssignmentLikeLayout::BreakAfterOperator] pub(crate) fn should_break_after_operator( right: &AnyJsExpression, diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/type-alias/conditional.ts.snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/type-alias/conditional.ts.snap index 25aaf7316daf..cdda3d6c71e1 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/type-alias/conditional.ts.snap +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/type-alias/conditional.ts.snap @@ -1,5 +1,6 @@ --- source: crates/biome_formatter_test/src/snapshot_builder.rs +assertion_line: 211 info: typescript/type-alias/conditional.ts --- # Input @@ -48,35 +49,9 @@ export type Intersect = ```diff --- Prettier +++ Biome -@@ -1,18 +1,27 @@ --type FallbackFlags = -- Equals["flags"], {}> extends true -- ? Dict -- : NonNullableFlag["flags"]; -+type FallbackFlags = Equals< -+ NonNullableFlag["flags"], -+ {} -+> extends true -+ ? Dict -+ : NonNullableFlag["flags"]; - --export type UnPromise> = -- Type extends Promise ? Generic : never; -+export type UnPromise> = Type extends Promise< -+ infer Generic -+> -+ ? Generic -+ : never; - --export type Equals = -- (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 -- ? true -- : false; -+export type Equals = (() => T extends X ? 1 : 2) extends < -+ T, -+>() => T extends Y ? 1 : 2 -+ ? true -+ : false; +@@ -11,8 +11,11 @@ + ? true + : false; -export type _Repeat = - __Repeat extends infer X ? Cast : never; @@ -93,24 +68,18 @@ export type Intersect = # Output ```ts -type FallbackFlags = Equals< - NonNullableFlag["flags"], - {} -> extends true - ? Dict - : NonNullableFlag["flags"]; - -export type UnPromise> = Type extends Promise< - infer Generic -> - ? Generic - : never; +type FallbackFlags = + Equals["flags"], {}> extends true + ? Dict + : NonNullableFlag["flags"]; -export type Equals = (() => T extends X ? 1 : 2) extends < - T, ->() => T extends Y ? 1 : 2 - ? true - : false; +export type UnPromise> = + Type extends Promise ? Generic : never; + +export type Equals = + (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 + ? true + : false; export type _Repeat< A extends any, diff --git a/crates/biome_js_formatter/tests/specs/ts/type/conditional.ts b/crates/biome_js_formatter/tests/specs/ts/type/conditional.ts index 3bb9bc516d23..22d631c4ced8 100644 --- a/crates/biome_js_formatter/tests/specs/ts/type/conditional.ts +++ b/crates/biome_js_formatter/tests/specs/ts/type/conditional.ts @@ -14,4 +14,30 @@ type T4 = test extends string // something ? unknown : test extends number ? undefined : // else - undefined; \ No newline at end of file + undefined; + +type T5 = + // comment + test extends string ? test extends number ? unknown : unknown : undefined; + +type Echo = T + +type T6 = test extends Echo ? test extends number ? unknown : unknown : undefined; + +type T7 = test extends Echo ? unknown : test extends number ? undefined : undefined; + +type T8 = test extends Echo ? +// something + unknown : test extends number ? undefined : + // else + undefined; + +type T9 = test extends Echo + // something + ? unknown : test extends number ? undefined : + // else + undefined; + +type T10 = + // comment + test extends Echo ? test extends number ? unknown : unknown : undefined; diff --git a/crates/biome_js_formatter/tests/specs/ts/type/conditional.ts.snap b/crates/biome_js_formatter/tests/specs/ts/type/conditional.ts.snap index 4a894ab6a1d6..07ddd4c68ccd 100644 --- a/crates/biome_js_formatter/tests/specs/ts/type/conditional.ts.snap +++ b/crates/biome_js_formatter/tests/specs/ts/type/conditional.ts.snap @@ -1,5 +1,6 @@ --- source: crates/biome_formatter_test/src/snapshot_builder.rs +assertion_line: 211 info: ts/type/conditional.ts --- # Input @@ -22,6 +23,33 @@ type T4 = test extends string ? unknown : test extends number ? undefined : // else undefined; + +type T5 = + // comment + test extends string ? test extends number ? unknown : unknown : undefined; + +type Echo = T + +type T6 = test extends Echo ? test extends number ? unknown : unknown : undefined; + +type T7 = test extends Echo ? unknown : test extends number ? undefined : undefined; + +type T8 = test extends Echo ? +// something + unknown : test extends number ? undefined : + // else + undefined; + +type T9 = test extends Echo + // something + ? unknown : test extends number ? undefined : + // else + undefined; + +type T10 = + // comment + test extends Echo ? test extends number ? unknown : unknown : undefined; + ``` @@ -79,4 +107,50 @@ type T4 = test extends string ? undefined : // else undefined; + +type T5 = + // comment + test extends string ? (test extends number ? unknown : unknown) : undefined; + +type Echo = T; + +type T6 = + test extends Echo + ? test extends number + ? unknown + : unknown + : undefined; + +type T7 = + test extends Echo + ? unknown + : test extends number + ? undefined + : undefined; + +type T8 = + test extends Echo + ? // something + unknown + : test extends number + ? undefined + : // else + undefined; + +type T9 = + test extends Echo + ? // something + unknown + : test extends number + ? undefined + : // else + undefined; + +type T10 = + // comment + test extends Echo + ? test extends number + ? unknown + : unknown + : undefined; ```