@@ -14030,7 +14030,6 @@ namespace ts {
14030
14030
// We ignore 'never' types in unions
14031
14031
if (!(flags & TypeFlags.Never)) {
14032
14032
includes |= flags & TypeFlags.IncludesMask;
14033
- if (flags & TypeFlags.StructuredOrInstantiable) includes |= TypeFlags.IncludesStructuredOrInstantiable;
14034
14033
if (type === wildcardType) includes |= TypeFlags.IncludesWildcard;
14035
14034
if (!strictNullChecks && flags & TypeFlags.Nullable) {
14036
14035
if (!(getObjectFlags(type) & ObjectFlags.ContainsWideningType)) includes |= TypeFlags.IncludesNonWideningType;
@@ -14337,13 +14336,19 @@ namespace ts {
14337
14336
if (flags & TypeFlags.AnyOrUnknown) {
14338
14337
if (type === wildcardType) includes |= TypeFlags.IncludesWildcard;
14339
14338
}
14340
- else if ((strictNullChecks || !(flags & TypeFlags.Nullable)) && !typeSet.has(type.id.toString())) {
14341
- if (type.flags & TypeFlags.Unit && includes & TypeFlags.Unit) {
14342
- // We have seen two distinct unit types which means we should reduce to an
14343
- // empty intersection. Adding TypeFlags.NonPrimitive causes that to happen.
14344
- includes |= TypeFlags.NonPrimitive;
14339
+ else if (strictNullChecks || !(flags & TypeFlags.Nullable)) {
14340
+ if (exactOptionalPropertyTypes && type === missingType) {
14341
+ includes |= TypeFlags.IncludesMissingType;
14342
+ type = undefinedType;
14343
+ }
14344
+ if (!typeSet.has(type.id.toString())) {
14345
+ if (type.flags & TypeFlags.Unit && includes & TypeFlags.Unit) {
14346
+ // We have seen two distinct unit types which means we should reduce to an
14347
+ // empty intersection. Adding TypeFlags.NonPrimitive causes that to happen.
14348
+ includes |= TypeFlags.NonPrimitive;
14349
+ }
14350
+ typeSet.set(type.id.toString(), type);
14345
14351
}
14346
- typeSet.set(type.id.toString(), type);
14347
14352
}
14348
14353
includes |= flags & TypeFlags.IncludesMask;
14349
14354
}
@@ -14418,14 +14423,14 @@ namespace ts {
14418
14423
return false;
14419
14424
}
14420
14425
14421
- function extractIrreducible(types: Type[], flag: TypeFlags) {
14422
- if (every(types, t => !!(t.flags & TypeFlags.Union) && some((t as UnionType).types, tt => !!(tt.flags & flag)))) {
14423
- for (let i = 0; i < types.length; i++) {
14424
- types[i] = filterType(types[i], t => !(t.flags & flag));
14425
- }
14426
- return true;
14426
+ function eachIsUnionContaining(types: Type[], flag: TypeFlags) {
14427
+ return every(types, t => !!(t.flags & TypeFlags.Union) && some((t as UnionType).types, tt => !!(tt.flags & flag)));
14428
+ }
14429
+
14430
+ function removeFromEach(types: Type[], flag: TypeFlags) {
14431
+ for (let i = 0; i < types.length; i++) {
14432
+ types[i] = filterType(types[i], t => !(t.flags & flag));
14427
14433
}
14428
- return false;
14429
14434
}
14430
14435
14431
14436
// If the given list of types contains more than one union of primitive types, replace the
@@ -14535,6 +14540,9 @@ namespace ts {
14535
14540
if (includes & TypeFlags.IncludesEmptyObject && includes & TypeFlags.Object) {
14536
14541
orderedRemoveItemAt(typeSet, findIndex(typeSet, isEmptyAnonymousObjectType));
14537
14542
}
14543
+ if (includes & TypeFlags.IncludesMissingType) {
14544
+ typeSet[typeSet.indexOf(undefinedType)] = missingType;
14545
+ }
14538
14546
if (typeSet.length === 0) {
14539
14547
return unknownType;
14540
14548
}
@@ -14551,10 +14559,13 @@ namespace ts {
14551
14559
// reduced we'll never reduce again, so this occurs at most once.
14552
14560
result = getIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
14553
14561
}
14554
- else if (extractIrreducible(typeSet, TypeFlags.Undefined)) {
14555
- result = getUnionType([getIntersectionType(typeSet), undefinedType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
14562
+ else if (eachIsUnionContaining(typeSet, TypeFlags.Undefined)) {
14563
+ const undefinedOrMissingType = exactOptionalPropertyTypes && some(typeSet, t => containsType((t as UnionType).types, missingType)) ? missingType : undefinedType;
14564
+ removeFromEach(typeSet, TypeFlags.Undefined);
14565
+ result = getUnionType([getIntersectionType(typeSet), undefinedOrMissingType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
14556
14566
}
14557
- else if (extractIrreducible(typeSet, TypeFlags.Null)) {
14567
+ else if (eachIsUnionContaining(typeSet, TypeFlags.Null)) {
14568
+ removeFromEach(typeSet, TypeFlags.Null);
14558
14569
result = getUnionType([getIntersectionType(typeSet), nullType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
14559
14570
}
14560
14571
else {
0 commit comments