@@ -3910,25 +3910,23 @@ namespace ts {
3910
3910
return links.resolvedType;
3911
3911
}
3912
3912
3913
- function addTypeToSet(typeSet: Type[], type: Type, typeKind : TypeFlags) {
3914
- if (type.flags & typeKind ) {
3915
- addTypesToSet(typeSet, (<UnionOrIntersectionType>type).types, typeKind );
3913
+ function addTypeToSet(typeSet: Type[], type: Type, typeSetKind : TypeFlags) {
3914
+ if (type.flags & typeSetKind ) {
3915
+ addTypesToSet(typeSet, (<UnionOrIntersectionType>type).types, typeSetKind );
3916
3916
}
3917
3917
else if (!contains(typeSet, type)) {
3918
3918
typeSet.push(type);
3919
3919
}
3920
3920
}
3921
3921
3922
- function addTypesToSet(typeSet: Type[], types: Type[], typeKind: TypeFlags) {
3922
+ // Add the given types to the given type set. Order is preserved, duplicates are removed,
3923
+ // and nested types of the given kind are flattened into the set.
3924
+ function addTypesToSet(typeSet: Type[], types: Type[], typeSetKind: TypeFlags) {
3923
3925
for (let type of types) {
3924
- addTypeToSet(typeSet, type, typeKind );
3926
+ addTypeToSet(typeSet, type, typeSetKind );
3925
3927
}
3926
3928
}
3927
3929
3928
- function compareTypeIds(type1: Type, type2: Type): number {
3929
- return type1.id - type2.id;
3930
- }
3931
-
3932
3930
function isSubtypeOfAny(candidate: Type, types: Type[]): boolean {
3933
3931
for (let type of types) {
3934
3932
if (candidate !== type && isTypeSubtypeOf(candidate, type)) {
@@ -3967,6 +3965,10 @@ namespace ts {
3967
3965
}
3968
3966
}
3969
3967
3968
+ function compareTypeIds(type1: Type, type2: Type): number {
3969
+ return type1.id - type2.id;
3970
+ }
3971
+
3970
3972
// The noSubtypeReduction flag is there because it isn't possible to always do subtype reduction. The flag
3971
3973
// is true when creating a union type from a type node and when instantiating a union type. In both of those
3972
3974
// cases subtype reduction has to be deferred to properly support recursive union types. For example, a
@@ -4031,8 +4033,11 @@ namespace ts {
4031
4033
// type operator and we can't reduce those because we want to support recursive intersection types. For example,
4032
4034
// a type alias of the form "type List<T> = T & { next: List<T> }" cannot be reduced during its declaration.
4033
4035
// Also, unlike union types, the order of the constituent types is preserved in order that overload resolution
4034
- // for intersections of types with signatues can be deterministic.
4036
+ // for intersections of types with signatures can be deterministic.
4035
4037
function getIntersectionType(types: Type[]): Type {
4038
+ if (types.length === 0) {
4039
+ return emptyObjectType;
4040
+ }
4036
4041
let typeSet: Type[] = [];
4037
4042
addTypesToSet(typeSet, types, TypeFlags.Intersection);
4038
4043
if (containsTypeAny(typeSet)) {
@@ -4469,6 +4474,7 @@ namespace ts {
4469
4474
}
4470
4475
}
4471
4476
else if (relation !== identityRelation) {
4477
+ // Note that the "each" checks must precede the "some" checks to produce the correct results
4472
4478
if (source.flags & TypeFlags.Union) {
4473
4479
if (result = eachTypeRelatedToType(<UnionType>source, target, reportErrors)) {
4474
4480
return result;
@@ -4480,6 +4486,9 @@ namespace ts {
4480
4486
}
4481
4487
}
4482
4488
else {
4489
+ // A check of the form A | B = C & D can be satisfied either by having C be related to A | B,
4490
+ // D be related to A | B, C & D be related to A, or C & D be related to B. Thus, we need to
4491
+ // check both sides here.
4483
4492
if (source.flags & TypeFlags.Intersection) {
4484
4493
// If target is a union type the following check will report errors so we suppress them here
4485
4494
if (result = someTypeRelatedToType(<IntersectionType>source, target, reportErrors && !(target.flags & TypeFlags.Union))) {
@@ -4508,8 +4517,11 @@ namespace ts {
4508
4517
// it may hold in a structural comparison.
4509
4518
// Report structural errors only if we haven't reported any errors yet
4510
4519
let reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo;
4511
- // identity relation does not use apparent type
4520
+ // Identity relation does not use apparent type
4512
4521
let sourceOrApparentType = relation === identityRelation ? source : getApparentType(source);
4522
+ // In a check of the form X = A & B, we will have previously checked if A relates to X or B relates
4523
+ // to X. Failing both of those we want to check if the aggregation of A and B's members structurally
4524
+ // relates to X. Thus, we include intersection types on the source side here.
4513
4525
if (sourceOrApparentType.flags & (TypeFlags.ObjectType | TypeFlags.Intersection) && target.flags & TypeFlags.ObjectType) {
4514
4526
if (result = objectTypeRelatedTo(sourceOrApparentType, <ObjectType>target, reportStructuralErrors)) {
4515
4527
errorInfo = saveErrorInfo;
@@ -5423,7 +5435,9 @@ namespace ts {
5423
5435
}
5424
5436
}
5425
5437
// Next, if target is a union type containing a single naked type parameter, make a
5426
- // secondary inference to that type parameter
5438
+ // secondary inference to that type parameter. We don't do this for intersection types
5439
+ // because in a target type like Foo & T we don't know how which parts of the source type
5440
+ // should be matched by Foo and which should be inferred to T.
5427
5441
if (target.flags & TypeFlags.Union && typeParameterCount === 1) {
5428
5442
inferiority++;
5429
5443
inferFromTypes(source, typeParameter);
0 commit comments