@@ -20,7 +20,7 @@ use crate::{
2020 write,
2121 write:: {
2222 BinaryLikeExpression , FormatJsArrowFunctionExpression ,
23- FormatJsArrowFunctionExpressionOptions ,
23+ FormatJsArrowFunctionExpressionOptions , FormatWrite ,
2424 } ,
2525} ;
2626
@@ -32,7 +32,7 @@ pub enum AssignmentLike<'a, 'b> {
3232 AssignmentExpression ( & ' b AstNode < ' a , AssignmentExpression < ' a > > ) ,
3333 ObjectProperty ( & ' b AstNode < ' a , ObjectProperty < ' a > > ) ,
3434 PropertyDefinition ( & ' b AstNode < ' a , PropertyDefinition < ' a > > ) ,
35- // TODO: Add TSTypeAliasDeclaration when needed
35+ TSTypeAliasDeclaration ( & ' b AstNode < ' a , TSTypeAliasDeclaration < ' a > > ) ,
3636}
3737
3838/// Determines how a assignment like be formatted
@@ -224,6 +224,18 @@ impl<'a> AssignmentLike<'a, '_> {
224224
225225 Ok ( false ) // Class properties don't use "short" key logic
226226 }
227+ AssignmentLike :: TSTypeAliasDeclaration ( declaration) => {
228+ write ! (
229+ f,
230+ [
231+ declaration. declare. then_some( "declare " ) ,
232+ "type " ,
233+ declaration. id( ) ,
234+ declaration. type_parameters( )
235+ ]
236+ ) ?;
237+ Ok ( false )
238+ }
227239 }
228240 }
229241
@@ -244,6 +256,9 @@ impl<'a> AssignmentLike<'a, '_> {
244256 {
245257 write ! ( f, [ space( ) , "=" ] )
246258 }
259+ Self :: TSTypeAliasDeclaration ( _) => {
260+ write ! ( f, [ space( ) , "=" ] )
261+ }
247262 _ => Ok ( ( ) ) ,
248263 }
249264 }
@@ -274,6 +289,14 @@ impl<'a> AssignmentLike<'a, '_> {
274289 [ space( ) , with_assignment_layout( property. value( ) . unwrap( ) , Some ( layout) ) ]
275290 )
276291 }
292+ Self :: TSTypeAliasDeclaration ( declaration) => {
293+ if let AstNodes :: TSUnionType ( union) = declaration. type_annotation ( ) . as_ast_nodes ( ) {
294+ union. write ( f) ?;
295+ union. format_trailing_comments ( f)
296+ } else {
297+ write ! ( f, [ space( ) , declaration. type_annotation( ) ] )
298+ }
299+ }
277300 }
278301 }
279302
@@ -305,14 +328,14 @@ impl<'a> AssignmentLike<'a, '_> {
305328 return AssignmentLikeLayout :: NeverBreakAfterOperator ;
306329 }
307330
308- if self . should_break_left_hand_side ( ) {
309- return AssignmentLikeLayout :: BreakLeftHandSide ;
310- }
311-
312331 if self . should_break_after_operator ( right_expression, f) {
313332 return AssignmentLikeLayout :: BreakAfterOperator ;
314333 }
315334
335+ if self . should_break_left_hand_side ( ) {
336+ return AssignmentLikeLayout :: BreakLeftHandSide ;
337+ }
338+
316339 if is_left_short {
317340 return AssignmentLikeLayout :: NeverBreakAfterOperator ;
318341 }
@@ -370,14 +393,15 @@ impl<'a> AssignmentLike<'a, '_> {
370393 AssignmentLike :: PropertyDefinition ( property_class_member) => {
371394 property_class_member. value ( )
372395 }
396+ AssignmentLike :: TSTypeAliasDeclaration ( declaration) => None ,
373397 }
374398 }
375399
376400 /// Checks that a [AssignmentLike] consists only of the left part
377401 /// usually, when a [variable declarator](VariableDeclarator) doesn't have initializer
378402 fn has_only_left_hand_side ( & self ) -> bool {
379403 match self {
380- Self :: AssignmentExpression ( _) => false ,
404+ Self :: AssignmentExpression ( _) | Self :: TSTypeAliasDeclaration ( _ ) => false ,
381405 Self :: VariableDeclarator ( declarator) => declarator. init . is_none ( ) ,
382406 Self :: PropertyDefinition ( property) => property. value ( ) . is_none ( ) ,
383407 Self :: ObjectProperty ( property) => property. shorthand ,
@@ -441,17 +465,20 @@ impl<'a> AssignmentLike<'a, '_> {
441465 return true ;
442466 }
443467
444- // TODO: Add is_complex_type_alias when TypeAliasDeclaration is supported
445- let is_complex_type_alias = false ;
468+ if self . is_complex_type_alias ( ) {
469+ return true ;
470+ }
446471
447- if !self
448- . get_right_expression ( )
449- . is_some_and ( |expr| matches ! ( expr. as_ref( ) , Expression :: ArrowFunctionExpression ( _) ) )
450- {
472+ let Self :: VariableDeclarator ( declarator) = self else {
451473 return false ;
452- }
474+ } ;
453475
454- matches ! ( self , Self :: VariableDeclarator ( decl) if decl. id. type_annotation. as_ref( ) . is_some_and( |ann| is_complex_type_annotation( ann) ) )
476+ let type_annotation = declarator. id . type_annotation . as_ref ( ) ;
477+
478+ type_annotation. is_some_and ( |ann| is_complex_type_annotation ( ann) )
479+ || ( self . get_right_expression ( ) . is_some_and ( |expr| {
480+ matches ! ( expr. as_ref( ) , Expression :: ArrowFunctionExpression ( _) )
481+ } ) && type_annotation. is_some_and ( |ann| is_annotation_breakable ( ann) ) )
455482 }
456483
457484 /// Checks if the current assignment is eligible for [AssignmentLikeLayout::BreakAfterOperator]
@@ -466,33 +493,49 @@ impl<'a> AssignmentLike<'a, '_> {
466493 let comments = f. context ( ) . comments ( ) ;
467494 if let Some ( right_expression) = right_expression {
468495 should_break_after_operator ( right_expression, f)
496+ } else if let AssignmentLike :: TSTypeAliasDeclaration ( decl) = self {
497+ // For TSTypeAliasDeclaration, check if the type annotation is a union type with comments
498+ match & decl. type_annotation {
499+ TSType :: TSConditionalType ( conditional_type) => {
500+ let is_generic = |ts_type : & TSType < ' a > | -> bool {
501+ match ts_type {
502+ TSType :: TSFunctionType ( function) => function. type_parameters . is_some ( ) ,
503+ TSType :: TSTypeReference ( reference) => {
504+ reference. type_arguments . is_some ( )
505+ }
506+ _ => false ,
507+ }
508+ } ;
509+
510+ is_generic ( & conditional_type. check_type )
511+ || is_generic ( & conditional_type. extends_type )
512+ }
513+ _ => {
514+ // Check for leading comments on any other type
515+ comments. has_comment_before ( decl. type_annotation . span ( ) . start )
516+ }
517+ }
469518 } else {
470- // RightAssignmentLike::AnyTsType(AnyTsType::TsUnionType(ty)) => {
471- // // Recursively checks if the union type is nested and identifies the innermost union type.
472- // // If a leading comment is found while navigating to the inner union type,
473- // // it is considered as having leading comments.
474- // let mut union_type = ty.clone();
475- // let mut has_leading_comments = comments.has_leading_comments(union_type.syntax());
476- // while is_nested_union_type(&union_type)? && !has_leading_comments {
477- // if let Some(Ok(inner_union_type)) = union_type.types().last() {
478- // let inner_union_type = TsUnionType::cast(inner_union_type.into_syntax());
479- // if let Some(inner_union_type) = inner_union_type {
480- // has_leading_comments =
481- // comments.has_leading_comments(inner_union_type.syntax());
482- // union_type = inner_union_type;
483- // } else {
484- // break;
485- // }
486- // } else {
487- // break;
488- // }
489- // }
490- // has_leading_comments
491- // }
492519 false
493520 }
494521 }
495522
523+ fn is_complex_type_alias ( & self ) -> bool {
524+ let AssignmentLike :: TSTypeAliasDeclaration ( type_alias) = self else {
525+ return false ;
526+ } ;
527+
528+ let Some ( type_parameters) = & type_alias. type_parameters else {
529+ return false ;
530+ } ;
531+
532+ type_parameters. params . len ( ) > 1
533+ && type_parameters
534+ . params
535+ . iter ( )
536+ . any ( |param| param. constraint . is_some ( ) || param. default . is_some ( ) )
537+ }
538+
496539 fn is_complex_destructuring ( & self ) -> bool {
497540 match self {
498541 AssignmentLike :: VariableDeclarator ( variable_decorator) => {
@@ -522,7 +565,9 @@ impl<'a> AssignmentLike<'a, '_> {
522565 AssignmentTargetProperty :: AssignmentTargetPropertyProperty ( _) => true ,
523566 } )
524567 }
525- AssignmentLike :: ObjectProperty ( _) | AssignmentLike :: PropertyDefinition ( _) => false ,
568+ AssignmentLike :: ObjectProperty ( _)
569+ | AssignmentLike :: PropertyDefinition ( _)
570+ | AssignmentLike :: TSTypeAliasDeclaration ( _) => false ,
526571 }
527572 }
528573}
@@ -883,10 +928,7 @@ fn is_complex_type_arguments(type_arguments: &TSTypeParameterInstantiation) -> b
883928 let is_first_argument_complex = ts_type_argument_list. first ( ) . is_some_and ( |first_argument| {
884929 matches ! (
885930 first_argument,
886- TSType :: TSUnionType ( _)
887- | TSType :: TSIntersectionType ( _)
888- | TSType :: TSTupleType ( _)
889- | TSType :: TSTypeLiteral ( _)
931+ TSType :: TSUnionType ( _) | TSType :: TSIntersectionType ( _) | TSType :: TSTypeLiteral ( _)
890932 )
891933 } ) ;
892934
@@ -900,20 +942,6 @@ fn is_complex_type_arguments(type_arguments: &TSTypeParameterInstantiation) -> b
900942 false
901943}
902944
903- /// If a union type has only one type and it's a union type, then it's a nested union type
904- /// ```js
905- /// type A = | (A | B)
906- /// ^^^^^^^^^^
907- /// ```
908- /// The final format will only keep the inner union type
909- fn is_nested_union_type ( union_type : & TSUnionType ) -> bool {
910- if union_type. types . len ( ) == 1 {
911- let ty = & union_type. types [ 0 ] ;
912- return matches ! ( ty, TSType :: TSUnionType ( _) ) ;
913- }
914- false
915- }
916-
917945/// Checks if the annotation is breakable
918946fn is_annotation_breakable ( annotation : & TSTypeAnnotation ) -> bool {
919947 matches ! (
0 commit comments