Skip to content

Commit e53168e

Browse files
authored
fix(complex-types): handle imported types correctly (#82)
1 parent aaddbb5 commit e53168e

File tree

4 files changed

+370
-451
lines changed

4 files changed

+370
-451
lines changed

packages/complex-types/src/core/printer.ts

Lines changed: 107 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -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) ||

packages/complex-types/src/core/transformers/defineProps.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const transformDefineProps: Transformer = (printer, s, id) => {
2323
return;
2424
}
2525

26-
const printedType = printer.printType(virtualFileDefinePropsTypeNode);
26+
const printedType = printer.print(virtualFileDefinePropsTypeNode);
2727
const offset = scriptSetupBlock.startTagEnd;
2828

2929
s.overwrite(

0 commit comments

Comments
 (0)