@@ -4,7 +4,11 @@ use convert_case::{Case, Casing};
44
55impl super :: ToTypescript for syn:: ItemStruct {
66 fn convert_to_ts ( self , state : & mut BuildState , config : & crate :: BuildSettings ) {
7- let export = if config. uses_type_interface { "" } else { "export " } ;
7+ let export = if config. uses_type_interface {
8+ ""
9+ } else {
10+ "export "
11+ } ;
812 let casing = utils:: get_attribute_arg ( "serde" , "rename_all" , & self . attrs ) ;
913 let casing = utils:: parse_serde_case ( casing) ;
1014 state. types . push ( '\n' ) ;
@@ -14,27 +18,53 @@ impl super::ToTypescript for syn::ItemStruct {
1418
1519 let intersections = get_intersections ( & self . fields ) ;
1620
17- match intersections {
18- Some ( intersections) => {
21+ match (
22+ intersections,
23+ matches ! ( self . fields, syn:: Fields :: Unnamed ( _) ) ,
24+ ) {
25+ ( Some ( intersections) , false ) => {
1926 state. types . push_str ( & format ! (
20- "{export}type {struct_name}{generics} = {intersections} & {{ \n " ,
27+ "{export}type {struct_name}{generics} = {intersections} & " ,
2128 export = export,
2229 struct_name = self . ident,
2330 generics = utils:: extract_struct_generics( self . generics. clone( ) ) ,
2431 intersections = intersections
2532 ) ) ;
2633 }
27- None => {
34+ ( None , false ) => {
2835 state. types . push_str ( & format ! (
29- "{export}interface {interface_name}{generics} {{ \n " ,
36+ "{export}interface {interface_name}{generics} " ,
3037 interface_name = self . ident,
3138 generics = utils:: extract_struct_generics( self . generics. clone( ) )
3239 ) ) ;
3340 }
41+ ( None , true ) => {
42+ state. types . push_str ( & format ! (
43+ "{export}type {struct_name}{generics} = " ,
44+ export = export,
45+ struct_name = self . ident,
46+ generics = utils:: extract_struct_generics( self . generics. clone( ) ) ,
47+ ) ) ;
48+ }
49+ ( Some ( _) , true ) => {
50+ if crate :: DEBUG . try_get ( ) . is_some_and ( |d| * d) {
51+ println ! (
52+ "#[tsync] failed for struct {}. cannot flatten fields of tuple struct" ,
53+ self . ident
54+ ) ;
55+ }
56+ return ;
57+ }
58+ }
59+
60+ if let syn:: Fields :: Unnamed ( unnamed) = self . fields {
61+ process_tuple_fields ( unnamed, state) ;
62+ } else {
63+ state. types . push_str ( "{\n " ) ;
64+ process_fields ( self . fields , state, 2 , casing) ;
65+ state. types . push ( '}' ) ;
3466 }
3567
36- process_fields ( self . fields , state, 2 , casing) ;
37- state. types . push ( '}' ) ;
3868 state. types . push ( '\n' ) ;
3969 }
4070}
@@ -48,6 +78,11 @@ pub fn process_fields(
4878 let space = utils:: build_indentation ( indentation_amount) ;
4979 let case = case. into ( ) ;
5080 for field in fields {
81+ debug_assert ! (
82+ field. ident. is_some( ) ,
83+ "struct fields should have names, found unnamed field"
84+ ) ;
85+
5186 // Check if the field has the serde flatten attribute, if so, skip it
5287 let has_flatten_attr = utils:: get_attribute_arg ( "serde" , "flatten" , & field. attrs ) . is_some ( ) ;
5388 if has_flatten_attr {
@@ -77,6 +112,41 @@ pub fn process_fields(
77112 }
78113}
79114
115+ /// Process tuple fields
116+ ///
117+ /// NOTE: Currently, this function does not handle comments or attributes on tuple fields.
118+ ///
119+ /// # Example
120+ ///
121+ /// ```ignore
122+ /// struct Todo(String, u32);
123+ /// ```
124+ ///
125+ /// should become
126+ ///
127+ /// ```ignore
128+ /// type Todo = [string, number];
129+ /// ```
130+ pub ( crate ) fn process_tuple_fields ( fields : syn:: FieldsUnnamed , state : & mut BuildState ) {
131+ let out = fields
132+ . unnamed
133+ . into_iter ( )
134+ . map ( |field| {
135+ let field_type = convert_type ( & field. ty ) ;
136+ format ! ( "{field_type}" , field_type = field_type. ts_type)
137+ } )
138+ . collect :: < Vec < String > > ( ) ;
139+
140+ if out. is_empty ( ) {
141+ return ;
142+ } else if out. len ( ) == 1 {
143+ state. types . push_str ( & format ! ( "{}" , out[ 0 ] ) ) ;
144+ return ;
145+ } else {
146+ state. types . push_str ( & format ! ( "[ {} ]" , out. join( ", " ) ) ) ;
147+ }
148+ }
149+
80150fn get_intersections ( fields : & syn:: Fields ) -> Option < String > {
81151 let mut types = Vec :: new ( ) ;
82152
0 commit comments