@@ -631,7 +631,7 @@ namespace ts {
631
631
const literalTypes = createMap<LiteralType>();
632
632
const indexedAccessTypes = createMap<IndexedAccessType>();
633
633
const substitutionTypes = createMap<SubstitutionType>();
634
- const structuralTags = createMap<StructuralTagType >();
634
+ const structuralTags = createMap<Type >();
635
635
const evolvingArrayTypes: EvolvingArrayType[] = [];
636
636
const undefinedProperties = createMap<Symbol>() as UnderscoreEscapedMap<Symbol>;
637
637
@@ -3801,8 +3801,33 @@ namespace ts {
3801
3801
return typeToTypeNodeHelper((<SubstitutionType>type).typeVariable, context);
3802
3802
}
3803
3803
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
+ }
3804
3829
context.approximateLength += 4;
3805
- return createTypeOperatorNode(SyntaxKind.TagKeyword, typeToTypeNodeHelper((type as StructuralTagType).type , context));
3830
+ return createTypeOperatorNode(SyntaxKind.TagKeyword, typeToTypeNodeHelper(innerType , context));
3806
3831
}
3807
3832
3808
3833
return Debug.fail("Should be unreachable.");
@@ -9980,14 +10005,17 @@ namespace ts {
9980
10005
includes = addTypeToIntersection(typeSet, includes, getRegularTypeOfLiteralType(type), tagSet);
9981
10006
}
9982
10007
if (isTopLevel && tagSet.size) {
9983
- let tag: StructuralTagType ;
10008
+ let tag: Type ;
9984
10009
if (tagSet.size === 1) {
9985
10010
tag = tagSet.values().next().value;
9986
10011
}
9987
10012
else {
9988
10013
const tagTypes: Type[] = [];
9989
10014
tagSet.forEach(t => tagTypes.push(t.type));
9990
10015
tag = getStructuralTagForType(getIntersectionType(tagTypes));
10016
+ if (tag.flags & TypeFlags.Union) {
10017
+ includes |= TypeFlags.Union;
10018
+ }
9991
10019
}
9992
10020
typeSet.set(tag.id.toString(), tag);
9993
10021
}
@@ -10310,11 +10338,19 @@ namespace ts {
10310
10338
return type;
10311
10339
}
10312
10340
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
+ }
10314
10345
const tid = "" + getTypeId(type);
10315
10346
if (structuralTags.has(tid)) {
10316
10347
return structuralTags.get(tid)!;
10317
10348
}
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
+ }
10318
10354
const tag = createType(TypeFlags.StructuralTag) as StructuralTagType;
10319
10355
tag.type = type;
10320
10356
tag.aliasSymbol = aliasSymbol;
0 commit comments