Skip to content

Commit 7325c89

Browse files
authored
Merge pull request #15938 from Microsoft/retain-undefined-in-spreads-w/strictNullChecks
Retain undefined in spreads with strict null checks
2 parents ada39c5 + 4e03d7b commit 7325c89

File tree

6 files changed

+107
-169
lines changed

6 files changed

+107
-169
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7640,11 +7640,11 @@ namespace ts {
76407640
if (members.has(leftProp.name)) {
76417641
const rightProp = members.get(leftProp.name);
76427642
const rightType = getTypeOfSymbol(rightProp);
7643-
if (maybeTypeOfKind(rightType, TypeFlags.Undefined) || rightProp.flags & SymbolFlags.Optional) {
7643+
if (rightProp.flags & SymbolFlags.Optional) {
76447644
const declarations: Declaration[] = concatenate(leftProp.declarations, rightProp.declarations);
76457645
const flags = SymbolFlags.Property | (leftProp.flags & SymbolFlags.Optional);
76467646
const result = createSymbol(flags, leftProp.name);
7647-
result.type = getUnionType([getTypeOfSymbol(leftProp), getTypeWithFacts(rightType, TypeFacts.NEUndefined)]);
7647+
result.type = getUnionType([getTypeOfSymbol(leftProp), rightType]);
76487648
result.leftSpread = leftProp;
76497649
result.rightSpread = rightProp;
76507650
result.declarations = declarations;
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
tests/cases/conformance/types/spread/objectSpreadStrictNull.ts(9,9): error TS2322: Type '{ sn: string | number | undefined; }' is not assignable to type '{ sn: string | number; }'.
2+
Types of property 'sn' are incompatible.
3+
Type 'string | number | undefined' is not assignable to type 'string | number'.
4+
Type 'undefined' is not assignable to type 'string | number'.
5+
tests/cases/conformance/types/spread/objectSpreadStrictNull.ts(10,9): error TS2322: Type '{ sn: string | number | undefined; }' is not assignable to type '{ sn: string | number; }'.
6+
Types of property 'sn' are incompatible.
7+
Type 'string | number | undefined' is not assignable to type 'string | number'.
8+
Type 'undefined' is not assignable to type 'string | number'.
9+
tests/cases/conformance/types/spread/objectSpreadStrictNull.ts(14,9): error TS2322: Type '{ sn: number | undefined; }' is not assignable to type '{ sn: string | number; }'.
10+
Types of property 'sn' are incompatible.
11+
Type 'number | undefined' is not assignable to type 'string | number'.
12+
Type 'undefined' is not assignable to type 'string | number'.
13+
tests/cases/conformance/types/spread/objectSpreadStrictNull.ts(15,9): error TS2322: Type '{ sn: number | undefined; }' is not assignable to type '{ sn: string | number; }'.
14+
Types of property 'sn' are incompatible.
15+
Type 'number | undefined' is not assignable to type 'string | number'.
16+
Type 'undefined' is not assignable to type 'string | number'.
17+
tests/cases/conformance/types/spread/objectSpreadStrictNull.ts(18,9): error TS2322: Type '{ sn: string | number | undefined; }' is not assignable to type '{ sn: string | number | boolean; }'.
18+
Types of property 'sn' are incompatible.
19+
Type 'string | number | undefined' is not assignable to type 'string | number | boolean'.
20+
Type 'undefined' is not assignable to type 'string | number | boolean'.
21+
tests/cases/conformance/types/spread/objectSpreadStrictNull.ts(28,7): error TS2322: Type '{ title: undefined; yearReleased: number; }' is not assignable to type 'Movie'.
22+
Types of property 'title' are incompatible.
23+
Type 'undefined' is not assignable to type 'string'.
24+
25+
26+
==== tests/cases/conformance/types/spread/objectSpreadStrictNull.ts (6 errors) ====
27+
function f(
28+
definiteBoolean: { sn: boolean },
29+
definiteString: { sn: string },
30+
optionalString: { sn?: string },
31+
optionalNumber: { sn?: number },
32+
undefinedString: { sn: string | undefined },
33+
undefinedNumber: { sn: number | undefined }) {
34+
// optional
35+
let optionalUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalNumber };
36+
~~~~~~~~~~~~~~~~~~
37+
!!! error TS2322: Type '{ sn: string | number | undefined; }' is not assignable to type '{ sn: string | number; }'.
38+
!!! error TS2322: Types of property 'sn' are incompatible.
39+
!!! error TS2322: Type 'string | number | undefined' is not assignable to type 'string | number'.
40+
!!! error TS2322: Type 'undefined' is not assignable to type 'string | number'.
41+
let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber };
42+
~~~~~~~~~~~~~~~~~~~~~~~
43+
!!! error TS2322: Type '{ sn: string | number | undefined; }' is not assignable to type '{ sn: string | number; }'.
44+
!!! error TS2322: Types of property 'sn' are incompatible.
45+
!!! error TS2322: Type 'string | number | undefined' is not assignable to type 'string | number'.
46+
!!! error TS2322: Type 'undefined' is not assignable to type 'string | number'.
47+
let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber };
48+
49+
// undefined
50+
let undefinedUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedNumber };
51+
~~~~~~~~~~~~~~~~~~~
52+
!!! error TS2322: Type '{ sn: number | undefined; }' is not assignable to type '{ sn: string | number; }'.
53+
!!! error TS2322: Types of property 'sn' are incompatible.
54+
!!! error TS2322: Type 'number | undefined' is not assignable to type 'string | number'.
55+
!!! error TS2322: Type 'undefined' is not assignable to type 'string | number'.
56+
let undefinedUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber };
57+
~~~~~~~~~~~~~~~~~~~~~~~~
58+
!!! error TS2322: Type '{ sn: number | undefined; }' is not assignable to type '{ sn: string | number; }'.
59+
!!! error TS2322: Types of property 'sn' are incompatible.
60+
!!! error TS2322: Type 'number | undefined' is not assignable to type 'string | number'.
61+
!!! error TS2322: Type 'undefined' is not assignable to type 'string | number'.
62+
let allUndefined: { sn: string | number | undefined } = { ...undefinedString, ...undefinedNumber };
63+
64+
let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber };
65+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
66+
!!! error TS2322: Type '{ sn: string | number | undefined; }' is not assignable to type '{ sn: string | number | boolean; }'.
67+
!!! error TS2322: Types of property 'sn' are incompatible.
68+
!!! error TS2322: Type 'string | number | undefined' is not assignable to type 'string | number | boolean'.
69+
!!! error TS2322: Type 'undefined' is not assignable to type 'string | number | boolean'.
70+
}
71+
72+
type Movie = {
73+
title: string;
74+
yearReleased: number;
75+
}
76+
77+
const m = { title: "The Matrix", yearReleased: 1999 };
78+
// should error here because title: undefined is not assignable to string
79+
const x: Movie = { ...m, title: undefined };
80+
~
81+
!!! error TS2322: Type '{ title: undefined; yearReleased: number; }' is not assignable to type 'Movie'.
82+
!!! error TS2322: Types of property 'title' are incompatible.
83+
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
84+

tests/baselines/reference/objectSpreadStrictNull.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ function f(
1818

1919
let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber };
2020
}
21+
22+
type Movie = {
23+
title: string;
24+
yearReleased: number;
25+
}
26+
27+
const m = { title: "The Matrix", yearReleased: 1999 };
28+
// should error here because title: undefined is not assignable to string
29+
const x: Movie = { ...m, title: undefined };
2130

2231

2332
//// [objectSpreadStrictNull.js]
@@ -40,3 +49,6 @@ function f(definiteBoolean, definiteString, optionalString, optionalNumber, unde
4049
var allUndefined = __assign({}, undefinedString, undefinedNumber);
4150
var undefinedWithOptionalContinues = __assign({}, definiteBoolean, undefinedString, optionalNumber);
4251
}
52+
var m = { title: "The Matrix", yearReleased: 1999 };
53+
// should error here because title: undefined is not assignable to string
54+
var x = __assign({}, m, { title: undefined });

tests/baselines/reference/objectSpreadStrictNull.symbols

Lines changed: 0 additions & 80 deletions
This file was deleted.

tests/baselines/reference/objectSpreadStrictNull.types

Lines changed: 0 additions & 87 deletions
This file was deleted.

tests/cases/conformance/types/spread/objectSpreadStrictNull.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,12 @@ function f(
1919

2020
let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber };
2121
}
22+
23+
type Movie = {
24+
title: string;
25+
yearReleased: number;
26+
}
27+
28+
const m = { title: "The Matrix", yearReleased: 1999 };
29+
// should error here because title: undefined is not assignable to string
30+
const x: Movie = { ...m, title: undefined };

0 commit comments

Comments
 (0)