Skip to content

Commit 30d0cdc

Browse files
committed
Ensure common supertype retains nullability
1 parent b288657 commit 30d0cdc

File tree

2 files changed

+17
-8
lines changed

2 files changed

+17
-8
lines changed

src/compiler/checker.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21228,7 +21228,17 @@ namespace ts {
2122821228
const primaryTypes = filter(types, t => !(t.flags & TypeFlags.Nullable));
2122921229
if (primaryTypes.length) {
2123021230
const supertypeOrUnion = getSupertypeOrUnion(primaryTypes);
21231-
return primaryTypes === types ? supertypeOrUnion : getUnionType([supertypeOrUnion, ...filter(types, t => !!(t.flags & TypeFlags.Nullable))]);
21231+
const supertypeOrUnionFacts = getTypeFacts(supertypeOrUnion);
21232+
const allFacts = getAllTypeFacts(types);
21233+
21234+
let missingNullableFlags: TypeFlags = 0;
21235+
if (allFacts & TypeFacts.IsNull && !(supertypeOrUnionFacts & TypeFacts.IsNull)) {
21236+
missingNullableFlags |= TypeFlags.Null;
21237+
}
21238+
if (allFacts & TypeFacts.IsUndefined && !(supertypeOrUnionFacts & TypeFacts.IsUndefined)) {
21239+
missingNullableFlags |= TypeFlags.Undefined;
21240+
}
21241+
return getNullableType(supertypeOrUnion, missingNullableFlags);
2123221242
}
2123321243
return getUnionType(types, UnionReduction.Subtype);
2123421244
}
@@ -23717,14 +23727,18 @@ namespace ts {
2371723727
return TypeFacts.None;
2371823728
}
2371923729
if (flags & TypeFlags.Union) {
23720-
return reduceLeft((type as UnionType).types, (facts, t) => facts | getTypeFacts(t), TypeFacts.None);
23730+
return getAllTypeFacts((type as UnionType).types);
2372123731
}
2372223732
if (flags & TypeFlags.Intersection) {
2372323733
return getIntersectionTypeFacts(type as IntersectionType);
2372423734
}
2372523735
return TypeFacts.UnknownFacts;
2372623736
}
2372723737

23738+
function getAllTypeFacts(types: Type[]): TypeFacts {
23739+
return reduceLeft(types, (facts, t) => facts | getTypeFacts(t), TypeFacts.None);
23740+
}
23741+
2372823742
function getIntersectionTypeFacts(type: IntersectionType): TypeFacts {
2372923743
// When an intersection contains a primitive type we ignore object type constituents as they are
2373023744
// presumably type tags. For example, in string & { __kind__: "name" } we ignore the object type.

tests/baselines/reference/inferenceOfNullableObjectTypesWithCommonBase.errors.txt

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
tests/cases/compiler/inferenceOfNullableObjectTypesWithCommonBase.ts(10,15): error TS2345: Argument of type 'D | undefined' is not assignable to parameter of type 'B'.
2-
Type 'undefined' is not assignable to type 'B'.
31
tests/cases/compiler/inferenceOfNullableObjectTypesWithCommonBase.ts(11,27): error TS2345: Argument of type 'B' is not assignable to parameter of type 'D'.
42
Property 'bar' is missing in type 'B' but required in type 'D'.
53

64

7-
==== tests/cases/compiler/inferenceOfNullableObjectTypesWithCommonBase.ts (2 errors) ====
5+
==== tests/cases/compiler/inferenceOfNullableObjectTypesWithCommonBase.ts (1 errors) ====
86
function equal<T>(a: T, b: T) { }
97

108
let v = null!;
@@ -15,9 +13,6 @@ tests/cases/compiler/inferenceOfNullableObjectTypesWithCommonBase.ts(11,27): err
1513
type D = { foo: string; bar: number }
1614

1715
equal(v as B, v as undefined | D)
18-
~~~~~~~~~~~~~~~~~~
19-
!!! error TS2345: Argument of type 'D | undefined' is not assignable to parameter of type 'B'.
20-
!!! error TS2345: Type 'undefined' is not assignable to type 'B'.
2116
equal(v as undefined | D, v as B)
2217
~~~~~~
2318
!!! error TS2345: Argument of type 'B' is not assignable to parameter of type 'D'.

0 commit comments

Comments
 (0)