@@ -43,6 +43,9 @@ function isTypeAlwaysSafeToExpand(type: ts.Type): boolean {
4343 return false ;
4444 }
4545 }
46+ if ( type . aliasSymbol != null ) {
47+ return false ;
48+ }
4649 return true ;
4750}
4851
@@ -447,7 +450,7 @@ export class TypeTable {
447450 this . isInShallowTypeContext ? TypeExtractionState . PendingShallow : TypeExtractionState . PendingFull ) ;
448451 // If the type is the self-type for a named type (not a generic instantiation of it),
449452 // 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 ) ) {
451454 this . selfTypes . symbols . push ( this . getSymbolId ( type . aliasSymbol || type . symbol ) ) ;
452455 this . selfTypes . selfTypes . push ( id ) ;
453456 }
@@ -533,7 +536,7 @@ export class TypeTable {
533536 let enclosingType = getEnclosingTypeOfThisType ( type ) ;
534537 if ( enclosingType != null ) {
535538 return "this;" + this . getId ( enclosingType , false ) ;
536- } else if ( symbol . parent == null ) {
539+ } else if ( symbol . parent == null || isFunctionTypeOrTypeAlias ( symbol . declarations ?. [ 0 ] ) ) {
537540 // The type variable is bound on a call signature. Only extract it by name.
538541 return "lextypevar;" + symbol . name ;
539542 } else {
@@ -614,14 +617,14 @@ export class TypeTable {
614617 // cannot be written using TypeScript syntax - so we ignore them entirely.
615618 return null ;
616619 }
617- return this . makeTypeStringVector ( "union" , unionType . types ) ;
620+ return this . makeDeduplicatedTypeStringVector ( "union" , unionType . types ) ;
618621 }
619622 if ( flags & ts . TypeFlags . Intersection ) {
620623 let intersectionType = type as ts . IntersectionType ;
621624 if ( intersectionType . types . length === 0 ) {
622625 return null ; // Ignore malformed type.
623626 }
624- return this . makeTypeStringVector ( "intersection" , intersectionType . types ) ;
627+ return this . makeDeduplicatedTypeStringVector ( "intersection" , intersectionType . types ) ;
625628 }
626629 if ( isTypeReference ( type ) && ( type . target . objectFlags & ts . ObjectFlags . Tuple ) ) {
627630 // 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 {
784787 return hash ;
785788 }
786789
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+
787811 /** Returns the type of `symbol` or `null` if it could not be computed. */
788812 private tryGetTypeOfSymbol ( symbol : ts . Symbol ) {
789813 try {
@@ -1328,3 +1352,35 @@ export class TypeTable {
13281352 }
13291353 }
13301354}
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