@@ -43,6 +43,9 @@ function isTypeAlwaysSafeToExpand(type: ts.Type): boolean {
43
43
return false ;
44
44
}
45
45
}
46
+ if ( type . aliasSymbol != null ) {
47
+ return false ;
48
+ }
46
49
return true ;
47
50
}
48
51
@@ -447,7 +450,7 @@ export class TypeTable {
447
450
this . isInShallowTypeContext ? TypeExtractionState . PendingShallow : TypeExtractionState . PendingFull ) ;
448
451
// If the type is the self-type for a named type (not a generic instantiation of it),
449
452
// emit the self-type binding for that type.
450
- if ( content . startsWith ( "reference;" ) && ! ( isTypeReference ( type ) && type . target !== type ) ) {
453
+ if ( content . startsWith ( "reference;" ) && isTypeSelfReference ( type ) ) {
451
454
this . selfTypes . symbols . push ( this . getSymbolId ( type . aliasSymbol || type . symbol ) ) ;
452
455
this . selfTypes . selfTypes . push ( id ) ;
453
456
}
@@ -533,7 +536,7 @@ export class TypeTable {
533
536
let enclosingType = getEnclosingTypeOfThisType ( type ) ;
534
537
if ( enclosingType != null ) {
535
538
return "this;" + this . getId ( enclosingType , false ) ;
536
- } else if ( symbol . parent == null ) {
539
+ } else if ( symbol . parent == null || isFunctionTypeOrTypeAlias ( symbol . declarations ?. [ 0 ] ) ) {
537
540
// The type variable is bound on a call signature. Only extract it by name.
538
541
return "lextypevar;" + symbol . name ;
539
542
} else {
@@ -614,14 +617,14 @@ export class TypeTable {
614
617
// cannot be written using TypeScript syntax - so we ignore them entirely.
615
618
return null ;
616
619
}
617
- return this . makeTypeStringVector ( "union" , unionType . types ) ;
620
+ return this . makeDeduplicatedTypeStringVector ( "union" , unionType . types ) ;
618
621
}
619
622
if ( flags & ts . TypeFlags . Intersection ) {
620
623
let intersectionType = type as ts . IntersectionType ;
621
624
if ( intersectionType . types . length === 0 ) {
622
625
return null ; // Ignore malformed type.
623
626
}
624
- return this . makeTypeStringVector ( "intersection" , intersectionType . types ) ;
627
+ return this . makeDeduplicatedTypeStringVector ( "intersection" , intersectionType . types ) ;
625
628
}
626
629
if ( isTypeReference ( type ) && ( type . target . objectFlags & ts . ObjectFlags . Tuple ) ) {
627
630
// Encode the minimum length and presence of rest element in the first two parts of the type string.
@@ -784,6 +787,27 @@ export class TypeTable {
784
787
return hash ;
785
788
}
786
789
790
+ /**
791
+ * Returns the given string with the IDs of the given types appended,
792
+ * ignoring duplicates, and each separated by `;`.
793
+ */
794
+ private makeDeduplicatedTypeStringVector ( tag : string , types : ReadonlyArray < ts . Type > , length = types . length ) : string | null {
795
+ let seenIds = new Set < number > ( ) ;
796
+ let numberOfSeenIds = 0 ;
797
+ let hash = tag ;
798
+ for ( let i = 0 ; i < length ; ++ i ) {
799
+ let id = this . getId ( types [ i ] , false ) ;
800
+ if ( id == null ) return null ;
801
+ seenIds . add ( id ) ;
802
+ if ( seenIds . size > numberOfSeenIds ) {
803
+ // This ID was not seen before
804
+ ++ numberOfSeenIds ;
805
+ hash += ";" + id ;
806
+ }
807
+ }
808
+ return hash ;
809
+ }
810
+
787
811
/** Returns the type of `symbol` or `null` if it could not be computed. */
788
812
private tryGetTypeOfSymbol ( symbol : ts . Symbol ) {
789
813
try {
@@ -1328,3 +1352,35 @@ export class TypeTable {
1328
1352
}
1329
1353
}
1330
1354
}
1355
+
1356
+ function isFunctionTypeOrTypeAlias ( declaration : ts . Declaration | undefined ) {
1357
+ if ( declaration == null ) return false ;
1358
+ return declaration . kind === ts . SyntaxKind . FunctionType || declaration . kind === ts . SyntaxKind . TypeAliasDeclaration ;
1359
+ }
1360
+
1361
+ /**
1362
+ * Given a `type` whose type-string is known to be a `reference`, returns true if this is the self-type for the referenced type.
1363
+ *
1364
+ * For example, for `type Foo<R> = ...` this returns true if `type` is `Foo<R>`.
1365
+ */
1366
+ function isTypeSelfReference ( type : ts . Type ) {
1367
+ if ( type . aliasSymbol != null ) {
1368
+ const { aliasTypeArguments } = type ;
1369
+ if ( aliasTypeArguments == null ) return true ;
1370
+ let declaration = type . aliasSymbol . declarations ?. [ 0 ] ;
1371
+ if ( declaration == null || declaration . kind !== ts . SyntaxKind . TypeAliasDeclaration ) return false ;
1372
+ let alias = declaration as ts . TypeAliasDeclaration ;
1373
+ for ( let i = 0 ; i < aliasTypeArguments . length ; ++ i ) {
1374
+ if ( aliasTypeArguments [ i ] . symbol ?. declarations ?. [ 0 ] !== alias . typeParameters [ i ] ) {
1375
+ return false ;
1376
+ }
1377
+ }
1378
+ return true ;
1379
+ } else if ( isTypeReference ( type ) ) {
1380
+ return type . target === type ;
1381
+ } else {
1382
+ // Return true because we know we have mapped this type to kind `reference`, and in the cases
1383
+ // not covered above (i.e. generic types) it is always a self-reference.
1384
+ return true ;
1385
+ }
1386
+ }
0 commit comments