@@ -18,11 +18,11 @@ export class Printer {
1818 }
1919
2020 private printIntersectionTypeNode ( node : ts . IntersectionTypeNode ) : string {
21- return node . types . map ( ( t ) => this . printType ( t ) ) . join ( " & " ) ;
21+ return node . types . map ( ( t ) => this . print ( t ) ) . join ( " & " ) ;
2222 }
2323
2424 private printUnionTypeNode ( node : ts . UnionTypeNode ) : string {
25- return node . types . map ( ( t ) => this . printType ( t ) ) . join ( " | " ) ;
25+ return node . types . map ( ( t ) => this . print ( t ) ) . join ( " | " ) ;
2626 }
2727
2828 private printTypeLiteralNode ( node : ts . TypeLiteralNode ) : string {
@@ -56,7 +56,7 @@ export class Printer {
5656 return parts . join ( "\n" ) ;
5757 }
5858
59- private printByType ( node : ts . Node ) : string {
59+ private printTypeByType ( node : ts . Node ) : string {
6060 const type = this . checker . getTypeAtLocation ( node ) ;
6161 const properties = type . getProperties ( ) ;
6262 const parts = [ "{" ] ;
@@ -85,7 +85,7 @@ export class Printer {
8585 return parts . join ( "\n" ) ;
8686 }
8787
88- private printIdentifier ( node : ts . Identifier ) : string {
88+ private printIdentifier ( node : ts . Identifier ) {
8989 const symbol = this . checker . getSymbolAtLocation ( node ) ;
9090 if ( ! symbol ) {
9191 return node . getText ( ) ;
@@ -96,59 +96,15 @@ export class Printer {
9696 return node . getText ( ) ;
9797 }
9898
99- // Try to resolve the type from the first declaration
100- const declaration = declarations [ 0 ] ;
101-
102- // Handle type alias declarations
103- if ( ts . isTypeAliasDeclaration ( declaration ) && declaration . type ) {
104- return this . printType ( declaration . type ) ;
105- }
106- // Handle interface declarations
107- else if ( ts . isInterfaceDeclaration ( declaration ) ) {
108- return this . printInterfaceDeclaration ( declaration ) ;
109- }
110- // Handle variable declarations with type annotations
111- else if ( ts . isVariableDeclaration ( declaration ) && declaration . type ) {
112- return this . printType ( declaration . type ) ;
113- }
114- // Handle type parameter declarations
115- else if ( ts . isTypeParameterDeclaration ( declaration ) ) {
116- if ( declaration . constraint ) {
117- return this . printType ( declaration . constraint ) ;
118- } else if ( declaration . default ) {
119- return this . printType ( declaration . default ) ;
120- }
121-
122- // Avoid keeping the original type
123- return "{}" ;
124- }
125- // Handle parameter declarations
126- else if ( ts . isParameter ( declaration ) && declaration . type ) {
127- return this . printType ( declaration . type ) ;
128- }
129-
130- // Fallback to type string representation
131- const type = this . checker . getTypeAtLocation ( node ) ;
132-
133- return this . checker . typeToString (
134- type ,
135- undefined ,
136- ts . TypeFormatFlags . NoTruncation ,
137- ) ;
99+ return this . print ( declarations [ 0 ] ) ;
138100 }
139101
140102 private printInterfaceDeclaration ( node : ts . InterfaceDeclaration ) : string {
141103 const parts = [ "{" ] ;
142104
143105 for ( const member of node . members ) {
144106 if ( ts . isPropertySignature ( member ) ) {
145- const stringBaseType = member . type
146- ? this . checker . typeToString (
147- this . getBaseType ( member . type ) ,
148- undefined ,
149- ts . TypeFormatFlags . NoTruncation ,
150- )
151- : "any" ;
107+ const stringBaseType = member . type ? this . print ( member . type ) : "any" ;
152108
153109 parts . push (
154110 [
@@ -190,7 +146,14 @@ export class Printer {
190146
191147 parts . push ( "}" ) ;
192148
193- return parts . join ( "\n" ) ;
149+ let result = parts . join ( "\n" ) ;
150+ if ( node . heritageClauses && node . heritageClauses . length > 0 ) {
151+ result = node . heritageClauses
152+ . map ( ( clause ) => this . print ( clause ) )
153+ . join ( " & " ) ;
154+ }
155+
156+ return result ;
194157 }
195158
196159 private printEnumDeclaration ( node : ts . EnumDeclaration ) : string {
@@ -280,31 +243,31 @@ export class Printer {
280243 private printFunctionTypeNode ( node : ts . FunctionTypeNode ) : string {
281244 const parameters = node . parameters
282245 . map ( ( param ) => {
283- const paramType = param . type ? this . printType ( param . type ) : "any" ;
246+ const paramType = param . type ? this . print ( param . type ) : "any" ;
284247 const optional = param . questionToken ? "?" : "" ;
285248 const rest = param . dotDotDotToken ? "..." : "" ;
286249
287250 return `${ rest } ${ param . name . getText ( ) } ${ optional } : ${ paramType } ` ;
288251 } )
289252 . join ( ", " ) ;
290253
291- const returnType = node . type ? this . printType ( node . type ) : "any" ;
254+ const returnType = node . type ? this . print ( node . type ) : "any" ;
292255
293256 return `(${ parameters } ) => ${ returnType } ` ;
294257 }
295258
296259 private printConstructorTypeNode ( node : ts . ConstructorTypeNode ) : string {
297260 const parameters = node . parameters
298261 . map ( ( param ) => {
299- const paramType = param . type ? this . printType ( param . type ) : "any" ;
262+ const paramType = param . type ? this . print ( param . type ) : "any" ;
300263 const optional = param . questionToken ? "?" : "" ;
301264 const rest = param . dotDotDotToken ? "..." : "" ;
302265
303266 return `${ rest } ${ param . name . getText ( ) } ${ optional } : ${ paramType } ` ;
304267 } )
305268 . join ( ", " ) ;
306269
307- const returnType = node . type ? this . printType ( node . type ) : "any" ;
270+ const returnType = node . type ? this . print ( node . type ) : "any" ;
308271
309272 return `new (${ parameters } ) => ${ returnType } ` ;
310273 }
@@ -316,47 +279,95 @@ export class Printer {
316279 }
317280
318281 private printArrayTypeNode ( node : ts . ArrayTypeNode ) : string {
319- return `${ this . printType ( node . elementType ) } []` ;
282+ return `${ this . print ( node . elementType ) } []` ;
320283 }
321284
322285 private printTupleTypeNode ( node : ts . TupleTypeNode ) : string {
323286 const elements = node . elements . map ( ( element ) => {
324287 if ( ts . isRestTypeNode ( element ) ) {
325- return `...${ this . printType ( element . type ) } ` ;
288+ return `...${ this . print ( element . type ) } ` ;
326289 }
327290 if ( ts . isOptionalTypeNode ( element ) ) {
328- return `${ this . printType ( element . type ) } ?` ;
291+ return `${ this . print ( element . type ) } ?` ;
329292 }
330293 if ( ts . isNamedTupleMember ( element ) ) {
331- const type = this . printType ( element . type ) ;
294+ const type = this . print ( element . type ) ;
332295 const optional = element . questionToken ? "?" : "" ;
333296 const rest = element . dotDotDotToken ? "..." : "" ;
334297
335298 return `${ rest } ${ element . name . getText ( ) } ${ optional } : ${ type } ` ;
336299 }
337300
338- return this . printType ( element ) ;
301+ return this . print ( element ) ;
339302 } ) ;
340303
341304 return `[${ elements . join ( ", " ) } ]` ;
342305 }
343306
344307 private printConditionalTypeNode ( node : ts . ConditionalTypeNode ) : string {
345- const checkType = this . printType ( node . checkType ) ;
346- const extendsType = this . printType ( node . extendsType ) ;
347- const trueType = this . printType ( node . trueType ) ;
348- const falseType = this . printType ( node . falseType ) ;
308+ const checkType = this . print ( node . checkType ) ;
309+ const extendsType = this . print ( node . extendsType ) ;
310+ const trueType = this . print ( node . trueType ) ;
311+ const falseType = this . print ( node . falseType ) ;
349312
350313 return `${ checkType } extends ${ extendsType } ? ${ trueType } : ${ falseType } ` ;
351314 }
352315
353316 private printIndexedAccessTypeNode ( node : ts . IndexedAccessTypeNode ) : string {
354- const objectType = this . printType ( node . objectType ) ;
355- const indexType = this . printType ( node . indexType ) ;
317+ const objectType = this . print ( node . objectType ) ;
318+ const indexType = this . print ( node . indexType ) ;
356319
357320 return `${ objectType } [${ indexType } ]` ;
358321 }
359322
323+ private printHeritageClause ( node : ts . HeritageClause ) : string {
324+ if ( node . token === ts . SyntaxKind . ExtendsKeyword ) {
325+ const parts = [ ] ;
326+
327+ for ( const type of node . types ) {
328+ if ( ts . isExpressionWithTypeArguments ( type ) ) {
329+ parts . push ( this . print ( type . expression ) ) ;
330+ }
331+ }
332+
333+ return parts . join ( " & " ) ;
334+ }
335+
336+ return "" ;
337+ }
338+
339+ private printImportSpecifier ( node : ts . ImportSpecifier ) : string {
340+ const name = node . propertyName
341+ ? node . propertyName . getText ( )
342+ : node . name . getText ( ) ;
343+ const symbol = this . checker . getSymbolAtLocation ( node . name ) ;
344+ if ( ! symbol ) {
345+ return name ;
346+ }
347+
348+ const aliasedSymbol = this . checker . getAliasedSymbol ( symbol ) ;
349+ const targetSymbol = aliasedSymbol || symbol ;
350+
351+ const declarations = targetSymbol . getDeclarations ( ) ;
352+ if ( ! declarations || declarations . length === 0 ) {
353+ return name ;
354+ }
355+
356+ const declaration = declarations . find (
357+ ( decl ) =>
358+ ts . isTypeAliasDeclaration ( decl ) ||
359+ ts . isInterfaceDeclaration ( decl ) ||
360+ ts . isClassDeclaration ( decl ) ||
361+ ts . isEnumDeclaration ( decl ) ||
362+ ts . isVariableDeclaration ( decl ) ,
363+ ) ;
364+ if ( declaration ) {
365+ return this . print ( declaration ) ;
366+ }
367+
368+ return name ;
369+ }
370+
360371 private isKeywordTypeNode ( node : ts . Node ) : boolean {
361372 return (
362373 node . kind === ts . SyntaxKind . StringKeyword ||
@@ -374,21 +385,23 @@ export class Printer {
374385 ) ;
375386 }
376387
377- public printType ( node : ts . Node ) : string {
378- if ( ts . isIntersectionTypeNode ( node ) ) {
388+ public print ( node : ts . Node ) : string {
389+ if ( ts . isIdentifier ( node ) ) {
390+ return this . printIdentifier ( node ) ;
391+ } else if ( ts . isIntersectionTypeNode ( node ) ) {
379392 return this . printIntersectionTypeNode ( node ) ;
380393 } else if ( ts . isUnionTypeNode ( node ) ) {
381394 return this . printUnionTypeNode ( node ) ;
382395 } else if ( ts . isTypeLiteralNode ( node ) ) {
383396 return this . printTypeLiteralNode ( node ) ;
384- } else if ( ts . isMappedTypeNode ( node ) || ts . isTypeReferenceNode ( node ) ) {
385- return this . printByType ( node ) ;
386- } else if ( ts . isIdentifier ( node ) ) {
387- return this . printIdentifier ( node ) ;
397+ } else if ( ts . isMappedTypeNode ( node ) ) {
398+ return this . printTypeByType ( node ) ;
399+ } else if ( ts . isTypeReferenceNode ( node ) ) {
400+ return this . print ( node . typeName ) ;
388401 } else if ( ts . isInterfaceDeclaration ( node ) ) {
389402 return this . printInterfaceDeclaration ( node ) ;
390403 } else if ( ts . isTypeAliasDeclaration ( node ) ) {
391- return node . type ? this . printType ( node . type ) : "any" ;
404+ return node . type ? this . print ( node . type ) : "any" ;
392405 } else if ( ts . isEnumDeclaration ( node ) ) {
393406 return this . printEnumDeclaration ( node ) ;
394407 } else if ( ts . isClassDeclaration ( node ) ) {
@@ -408,7 +421,27 @@ export class Printer {
408421 } else if ( ts . isIndexedAccessTypeNode ( node ) ) {
409422 return this . printIndexedAccessTypeNode ( node ) ;
410423 } else if ( ts . isParenthesizedTypeNode ( node ) ) {
411- return this . printType ( node . type ) ;
424+ return this . print ( node . type ) ;
425+ } else if ( ts . isHeritageClause ( node ) ) {
426+ return this . printHeritageClause ( node ) ;
427+ } else if ( ts . isTypeAliasDeclaration ( node ) && node . type ) {
428+ return this . print ( node . type ) ;
429+ } else if ( ts . isInterfaceDeclaration ( node ) ) {
430+ return this . printInterfaceDeclaration ( node ) ;
431+ } else if ( ts . isVariableDeclaration ( node ) && node . type ) {
432+ return this . print ( node . type ) ;
433+ } else if ( ts . isImportSpecifier ( node ) ) {
434+ return this . printImportSpecifier ( node ) ;
435+ } else if ( ts . isTypeParameterDeclaration ( node ) ) {
436+ if ( node . constraint ) {
437+ return this . print ( node . constraint ) ;
438+ } else if ( node . default ) {
439+ return this . print ( node . default ) ;
440+ }
441+
442+ return "{}" ;
443+ } else if ( ts . isParameter ( node ) && node . type ) {
444+ return this . print ( node . type ) ;
412445 } else if (
413446 ts . isLiteralTypeNode ( node ) ||
414447 ts . isThisTypeNode ( node ) ||
0 commit comments