@@ -631,7 +631,7 @@ namespace ts {
631631 const literalTypes = createMap<LiteralType>();
632632 const indexedAccessTypes = createMap<IndexedAccessType>();
633633 const substitutionTypes = createMap<SubstitutionType>();
634- const structuralTags = createMap<StructuralTagType >();
634+ const structuralTags = createMap<Type >();
635635 const evolvingArrayTypes: EvolvingArrayType[] = [];
636636 const undefinedProperties = createMap<Symbol>() as UnderscoreEscapedMap<Symbol>;
637637
@@ -3801,8 +3801,33 @@ namespace ts {
38013801 return typeToTypeNodeHelper((<SubstitutionType>type).typeVariable, context);
38023802 }
38033803 if (type.flags & TypeFlags.StructuralTag) {
3804+ const innerType = (type as StructuralTagType).type;
3805+ if (innerType.flags & TypeFlags.Intersection) {
3806+ // If some inner type of the intersection has an alias when hoisted out, (attempt to) hoist out all of the aliasable things
3807+ if (some((innerType as IntersectionType).types, t => !!getStructuralTagForType(t).aliasSymbol)) {
3808+ const aliasingTypes: Type[] = [];
3809+ const nonAliasingTypes: Type[] = [];
3810+ for (const t of (innerType as IntersectionType).types) {
3811+ const taggedVersion = getStructuralTagForType(t);
3812+ if (taggedVersion.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || isTypeSymbolAccessible(taggedVersion.aliasSymbol, context.enclosingDeclaration))) {
3813+ aliasingTypes.push(taggedVersion);
3814+ }
3815+ else {
3816+ nonAliasingTypes.push(t);
3817+ }
3818+ }
3819+ if (length(aliasingTypes)) {
3820+ if (length(nonAliasingTypes)) {
3821+ aliasingTypes.push(getStructuralTagForType(getIntersectionType(nonAliasingTypes)));
3822+ }
3823+ // Do note: this can make an intersection become nested within another intersection - this _is_ handled correctly
3824+ // during emit, so is fine (and honestly is more clear, since it groups all the tags together)
3825+ return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, map(aliasingTypes, t => typeToTypeNodeHelper(t, context)));
3826+ }
3827+ }
3828+ }
38043829 context.approximateLength += 4;
3805- return createTypeOperatorNode(SyntaxKind.TagKeyword, typeToTypeNodeHelper((type as StructuralTagType).type , context));
3830+ return createTypeOperatorNode(SyntaxKind.TagKeyword, typeToTypeNodeHelper(innerType , context));
38063831 }
38073832
38083833 return Debug.fail("Should be unreachable.");
@@ -9980,14 +10005,17 @@ namespace ts {
998010005 includes = addTypeToIntersection(typeSet, includes, getRegularTypeOfLiteralType(type), tagSet);
998110006 }
998210007 if (isTopLevel && tagSet.size) {
9983- let tag: StructuralTagType ;
10008+ let tag: Type ;
998410009 if (tagSet.size === 1) {
998510010 tag = tagSet.values().next().value;
998610011 }
998710012 else {
998810013 const tagTypes: Type[] = [];
998910014 tagSet.forEach(t => tagTypes.push(t.type));
999010015 tag = getStructuralTagForType(getIntersectionType(tagTypes));
10016+ if (tag.flags & TypeFlags.Union) {
10017+ includes |= TypeFlags.Union;
10018+ }
999110019 }
999210020 typeSet.set(tag.id.toString(), tag);
999310021 }
@@ -10310,11 +10338,19 @@ namespace ts {
1031010338 return type;
1031110339 }
1031210340
10313- function getStructuralTagForType(type: Type, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]) {
10341+ function getStructuralTagForType(type: Type, aliasSymbol?: Symbol | number, aliasTypeArguments?: readonly Type[]) {
10342+ if (typeof aliasSymbol === "number") {
10343+ aliasSymbol = undefined;
10344+ }
1031410345 const tid = "" + getTypeId(type);
1031510346 if (structuralTags.has(tid)) {
1031610347 return structuralTags.get(tid)!;
1031710348 }
10349+ if (type.flags & TypeFlags.Union) {
10350+ const union = getUnionType(map((type as UnionType).types, getStructuralTagForType), UnionReduction.Subtype, aliasSymbol, aliasTypeArguments);
10351+ structuralTags.set(tid, union);
10352+ return union;
10353+ }
1031810354 const tag = createType(TypeFlags.StructuralTag) as StructuralTagType;
1031910355 tag.type = type;
1032010356 tag.aliasSymbol = aliasSymbol;
0 commit comments