Skip to content

Commit 02fe2a7

Browse files
committed
fix: Crash when converting recursive type alias
Resolves #1547
1 parent ce218e9 commit 02fe2a7

File tree

3 files changed

+218
-6
lines changed

3 files changed

+218
-6
lines changed

src/lib/converter/types.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,6 @@ export function convertType(
121121
return requestBugReport(context, typeOrNode);
122122
}
123123

124-
// TS 4.2 added this to enable better tracking of type aliases.
125-
if (typeOrNode.isUnion() && typeOrNode.origin) {
126-
return convertType(context, typeOrNode.origin);
127-
}
128-
129124
// IgnoreErrors is important, without it, we can't assert that we will get a node.
130125
const node = context.checker.typeToTypeNode(
131126
typeOrNode,
@@ -952,6 +947,11 @@ const typeOperatorConverter: TypeConverter<ts.TypeOperatorNode> = {
952947
// keyof will only show up with generic functions, otherwise it gets eagerly
953948
// resolved to a union of strings.
954949
if (node.operator === ts.SyntaxKind.KeyOfKeyword) {
950+
// TS 4.2 added this to enable better tracking of type aliases.
951+
if (type.isUnion() && type.origin) {
952+
return convertType(context, type.origin);
953+
}
954+
955955
// There's probably an interface for this somewhere... I couldn't find it.
956956
const targetType = (type as ts.Type & { type: ts.Type }).type;
957957
return new TypeOperatorType(
@@ -974,6 +974,11 @@ const unionConverter: TypeConverter<ts.UnionTypeNode, ts.UnionType> = {
974974
);
975975
},
976976
convertType(context, type) {
977+
// TS 4.2 added this to enable better tracking of type aliases.
978+
if (type.origin) {
979+
return convertType(context, type.origin);
980+
}
981+
977982
return new UnionType(
978983
type.types.map((type) => convertType(context, type))
979984
);

src/test/converter/alias/alias.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,31 @@ export namespace GH1454 {
7373
export declare function bar(x: Bar): Bar;
7474
export declare function foo(x: Foo): Foo;
7575
}
76+
77+
export namespace GH1547 {
78+
export interface ThingA {
79+
type: "ThingA";
80+
}
81+
82+
export interface ThingB {
83+
type: "ThingB";
84+
}
85+
86+
type Things = ThingA | ThingB;
87+
88+
type ValueOrArray<T> = T | Array<ValueOrArray<T>>;
89+
90+
/**
91+
* Test.
92+
*/
93+
export class Test {
94+
/**
95+
* Log a thing.
96+
*
97+
* @param things - Array of things or a thing.
98+
*/
99+
log_thing(things: ValueOrArray<Things>): void {
100+
console.log(things);
101+
}
102+
}
103+
}

src/test/converter/alias/specs.json

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,184 @@
375375
}
376376
]
377377
},
378+
{
379+
"id": 52,
380+
"name": "GH1547",
381+
"kind": 2,
382+
"kindString": "Namespace",
383+
"flags": {},
384+
"children": [
385+
{
386+
"id": 57,
387+
"name": "Test",
388+
"kind": 128,
389+
"kindString": "Class",
390+
"flags": {},
391+
"comment": {
392+
"shortText": "Test."
393+
},
394+
"children": [
395+
{
396+
"id": 58,
397+
"name": "constructor",
398+
"kind": 512,
399+
"kindString": "Constructor",
400+
"flags": {},
401+
"signatures": [
402+
{
403+
"id": 59,
404+
"name": "new Test",
405+
"kind": 16384,
406+
"kindString": "Constructor signature",
407+
"flags": {},
408+
"type": {
409+
"type": "reference",
410+
"id": 57,
411+
"name": "Test"
412+
}
413+
}
414+
]
415+
},
416+
{
417+
"id": 60,
418+
"name": "log_thing",
419+
"kind": 2048,
420+
"kindString": "Method",
421+
"flags": {},
422+
"signatures": [
423+
{
424+
"id": 61,
425+
"name": "log_thing",
426+
"kind": 4096,
427+
"kindString": "Call signature",
428+
"flags": {},
429+
"comment": {
430+
"shortText": "Log a thing."
431+
},
432+
"parameters": [
433+
{
434+
"id": 62,
435+
"name": "things",
436+
"kind": 32768,
437+
"kindString": "Parameter",
438+
"flags": {},
439+
"comment": {
440+
"text": "Array of things or a thing.\n"
441+
},
442+
"type": {
443+
"type": "reference",
444+
"typeArguments": [
445+
{
446+
"type": "reference",
447+
"name": "Things"
448+
}
449+
],
450+
"name": "ValueOrArray"
451+
}
452+
}
453+
],
454+
"type": {
455+
"type": "intrinsic",
456+
"name": "void"
457+
}
458+
}
459+
]
460+
}
461+
],
462+
"groups": [
463+
{
464+
"title": "Constructors",
465+
"kind": 512,
466+
"children": [
467+
58
468+
]
469+
},
470+
{
471+
"title": "Methods",
472+
"kind": 2048,
473+
"children": [
474+
60
475+
]
476+
}
477+
]
478+
},
479+
{
480+
"id": 53,
481+
"name": "ThingA",
482+
"kind": 256,
483+
"kindString": "Interface",
484+
"flags": {},
485+
"children": [
486+
{
487+
"id": 54,
488+
"name": "type",
489+
"kind": 1024,
490+
"kindString": "Property",
491+
"flags": {},
492+
"type": {
493+
"type": "literal",
494+
"value": "ThingA"
495+
}
496+
}
497+
],
498+
"groups": [
499+
{
500+
"title": "Properties",
501+
"kind": 1024,
502+
"children": [
503+
54
504+
]
505+
}
506+
]
507+
},
508+
{
509+
"id": 55,
510+
"name": "ThingB",
511+
"kind": 256,
512+
"kindString": "Interface",
513+
"flags": {},
514+
"children": [
515+
{
516+
"id": 56,
517+
"name": "type",
518+
"kind": 1024,
519+
"kindString": "Property",
520+
"flags": {},
521+
"type": {
522+
"type": "literal",
523+
"value": "ThingB"
524+
}
525+
}
526+
],
527+
"groups": [
528+
{
529+
"title": "Properties",
530+
"kind": 1024,
531+
"children": [
532+
56
533+
]
534+
}
535+
]
536+
}
537+
],
538+
"groups": [
539+
{
540+
"title": "Classes",
541+
"kind": 128,
542+
"children": [
543+
57
544+
]
545+
},
546+
{
547+
"title": "Interfaces",
548+
"kind": 256,
549+
"children": [
550+
53,
551+
55
552+
]
553+
}
554+
]
555+
},
378556
{
379557
"id": 21,
380558
"name": "HorribleRecursiveTypeThatShouldNotBeUsedByAnyone",
@@ -884,7 +1062,8 @@
8841062
"children": [
8851063
28,
8861064
39,
887-
43
1065+
43,
1066+
52
8881067
]
8891068
},
8901069
{

0 commit comments

Comments
 (0)