@@ -196,7 +196,8 @@ namespace ts {
196
196
Source = 1 << 0,
197
197
Target = 1 << 1,
198
198
PropertyCheck = 1 << 2,
199
- InPropertyCheck = 1 << 3,
199
+ UnionIntersectionCheck = 1 << 3,
200
+ InPropertyCheck = 1 << 4,
200
201
}
201
202
202
203
const enum MappedTypeModifiers {
@@ -15621,38 +15622,14 @@ namespace ts {
15621
15622
// Note that these checks are specifically ordered to produce correct results. In particular,
15622
15623
// we need to deconstruct unions before intersections (because unions are always at the top),
15623
15624
// and we need to handle "each" relations before "some" relations for the same kind of type.
15624
- if (source.flags & TypeFlags.Union ) {
15625
- result = relation === comparableRelation ?
15626
- someTypeRelatedToType (source as UnionType , target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState ) :
15627
- eachTypeRelatedToType (source as UnionType , target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState );
15625
+ if (source.flags & TypeFlags.UnionOrIntersection || target.flags & TypeFlags.UnionOrIntersection ) {
15626
+ result = getConstituentCount(source) * getConstituentCount(target) >= 4 ?
15627
+ recursiveTypeRelatedTo (source, target, reportErrors, intersectionState | IntersectionState.UnionIntersectionCheck ) :
15628
+ structuredTypeRelatedTo (source, target, reportErrors, intersectionState | IntersectionState.UnionIntersectionCheck );
15628
15629
}
15629
- else {
15630
- if (target.flags & TypeFlags.Union) {
15631
- result = typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive));
15632
- }
15633
- else if (target.flags & TypeFlags.Intersection) {
15634
- result = typeRelatedToEachType(getRegularTypeOfObjectLiteral(source), target as IntersectionType, reportErrors, IntersectionState.Target);
15635
- }
15636
- else if (source.flags & TypeFlags.Intersection) {
15637
- // Check to see if any constituents of the intersection are immediately related to the target.
15638
- //
15639
- // Don't report errors though. Checking whether a constituent is related to the source is not actually
15640
- // useful and leads to some confusing error messages. Instead it is better to let the below checks
15641
- // take care of this, or to not elaborate at all. For instance,
15642
- //
15643
- // - For an object type (such as 'C = A & B'), users are usually more interested in structural errors.
15644
- //
15645
- // - For a union type (such as '(A | B) = (C & D)'), it's better to hold onto the whole intersection
15646
- // than to report that 'D' is not assignable to 'A' or 'B'.
15647
- //
15648
- // - For a primitive type or type parameter (such as 'number = A & B') there is no point in
15649
- // breaking the intersection apart.
15650
- result = someTypeRelatedToType(<IntersectionType>source, target, /*reportErrors*/ false, IntersectionState.Source);
15651
- }
15652
- if (!result && (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable)) {
15653
- if (result = recursiveTypeRelatedTo(source, target, reportErrors, intersectionState)) {
15654
- resetErrorInfo(saveErrorInfo);
15655
- }
15630
+ if (!result && !(source.flags & TypeFlags.Union) && (source.flags & (TypeFlags.StructuredOrInstantiable) || target.flags & TypeFlags.StructuredOrInstantiable)) {
15631
+ if (result = recursiveTypeRelatedTo(source, target, reportErrors, intersectionState)) {
15632
+ resetErrorInfo(saveErrorInfo);
15656
15633
}
15657
15634
}
15658
15635
if (!result && source.flags & (TypeFlags.Intersection | TypeFlags.TypeParameter)) {
@@ -16080,6 +16057,37 @@ namespace ts {
16080
16057
if (intersectionState & IntersectionState.PropertyCheck) {
16081
16058
return propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, IntersectionState.None);
16082
16059
}
16060
+ if (intersectionState & IntersectionState.UnionIntersectionCheck) {
16061
+ // Note that these checks are specifically ordered to produce correct results. In particular,
16062
+ // we need to deconstruct unions before intersections (because unions are always at the top),
16063
+ // and we need to handle "each" relations before "some" relations for the same kind of type.
16064
+ if (source.flags & TypeFlags.Union) {
16065
+ return relation === comparableRelation ?
16066
+ someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState & ~IntersectionState.UnionIntersectionCheck) :
16067
+ eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState & ~IntersectionState.UnionIntersectionCheck);
16068
+ }
16069
+ if (target.flags & TypeFlags.Union) {
16070
+ return typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive));
16071
+ }
16072
+ if (target.flags & TypeFlags.Intersection) {
16073
+ return typeRelatedToEachType(getRegularTypeOfObjectLiteral(source), target as IntersectionType, reportErrors, IntersectionState.Target);
16074
+ }
16075
+ // Source is an intersection. Check to see if any constituents of the intersection are immediately related
16076
+ // to the target.
16077
+ //
16078
+ // Don't report errors though. Checking whether a constituent is related to the source is not actually
16079
+ // useful and leads to some confusing error messages. Instead it is better to let the below checks
16080
+ // take care of this, or to not elaborate at all. For instance,
16081
+ //
16082
+ // - For an object type (such as 'C = A & B'), users are usually more interested in structural errors.
16083
+ //
16084
+ // - For a union type (such as '(A | B) = (C & D)'), it's better to hold onto the whole intersection
16085
+ // than to report that 'D' is not assignable to 'A' or 'B'.
16086
+ //
16087
+ // - For a primitive type or type parameter (such as 'number = A & B') there is no point in
16088
+ // breaking the intersection apart.
16089
+ return someTypeRelatedToType(<IntersectionType>source, target, /*reportErrors*/ false, IntersectionState.Source);
16090
+ }
16083
16091
const flags = source.flags & target.flags;
16084
16092
if (relation === identityRelation && !(flags & TypeFlags.Object)) {
16085
16093
if (flags & TypeFlags.Index) {
@@ -19645,6 +19653,10 @@ namespace ts {
19645
19653
return mappedTypes && getUnionType(mappedTypes, noReductions ? UnionReduction.None : UnionReduction.Literal);
19646
19654
}
19647
19655
19656
+ function getConstituentCount(type: Type) {
19657
+ return type.flags & TypeFlags.UnionOrIntersection ? (<UnionOrIntersectionType>type).types.length : 1;
19658
+ }
19659
+
19648
19660
function extractTypesOfKind(type: Type, kind: TypeFlags) {
19649
19661
return filterType(type, t => (t.flags & kind) !== 0);
19650
19662
}
0 commit comments