Skip to content

Commit cc005d1

Browse files
committed
Make spread overwrite error more lenient.
Fixes #46463, but I don't thik it's a good fix. See #46463 (comment) for discussion.
1 parent 460908a commit cc005d1

12 files changed

+150
-17
lines changed

src/compiler/checker.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27593,12 +27593,11 @@ namespace ts {
2759327593

2759427594
function checkSpreadPropOverrides(type: Type, props: SymbolTable, spread: SpreadAssignment | JsxSpreadAttribute) {
2759527595
for (const right of getPropertiesOfType(type)) {
27596-
if (!(right.flags & SymbolFlags.Optional)) {
27597-
const left = props.get(right.escapedName);
27598-
if (left) {
27599-
const diagnostic = error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName));
27600-
addRelatedInfo(diagnostic, createDiagnosticForNode(spread, Diagnostics.This_spread_always_overwrites_this_property));
27601-
}
27596+
const rightType = getTypeOfSymbol(right);
27597+
const left = props.get(right.escapedName);
27598+
if (left && (exactOptionalPropertyTypes || !maybeTypeOfKind(rightType, TypeFlags.Nullable)) && !(right.flags & SymbolFlags.Optional)) {
27599+
const diagnostic = error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName));
27600+
addRelatedInfo(diagnostic, createDiagnosticForNode(spread, Diagnostics.This_spread_always_overwrites_this_property));
2760227601
}
2760327602
}
2760427603
}

tests/baselines/reference/spreadDuplicate.errors.txt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
tests/cases/conformance/types/spread/spreadDuplicate.ts(10,12): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
2-
tests/cases/conformance/types/spread/spreadDuplicate.ts(12,12): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
32

43

5-
==== tests/cases/conformance/types/spread/spreadDuplicate.ts (2 errors) ====
4+
==== tests/cases/conformance/types/spread/spreadDuplicate.ts (1 errors) ====
65
// Repro from #44438
76

87
declare let a: { a: string };
@@ -18,13 +17,17 @@ tests/cases/conformance/types/spread/spreadDuplicate.ts(12,12): error TS2783: 'a
1817
!!! related TS2785 tests/cases/conformance/types/spread/spreadDuplicate.ts:10:20: This spread always overwrites this property.
1918
let b1 = { a: 123, ...b }; // string | number
2019
let c1 = { a: 123, ...c }; // string | undefined (Error)
21-
~~~~~~
22-
!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
23-
!!! related TS2785 tests/cases/conformance/types/spread/spreadDuplicate.ts:12:20: This spread always overwrites this property.
2420
let d1 = { a: 123, ...d }; // string | number
2521

2622
let a2 = { a: 123, ...(t ? a : {}) }; // string | number
2723
let b2 = { a: 123, ...(t ? b : {}) }; // string | number
2824
let c2 = { a: 123, ...(t ? c : {}) }; // string | number
2925
let d2 = { a: 123, ...(t ? d : {}) }; // string | number
26+
27+
// from #46463
28+
declare const conditional: boolean;
29+
const example = {
30+
color: "red", // OK
31+
...(conditional ? { color: "green" } : { size: "large" })
32+
}
3033

tests/baselines/reference/spreadDuplicate.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ let a2 = { a: 123, ...(t ? a : {}) }; // string | number
1717
let b2 = { a: 123, ...(t ? b : {}) }; // string | number
1818
let c2 = { a: 123, ...(t ? c : {}) }; // string | number
1919
let d2 = { a: 123, ...(t ? d : {}) }; // string | number
20+
21+
// from #46463
22+
declare const conditional: boolean;
23+
const example = {
24+
color: "red", // OK
25+
...(conditional ? { color: "green" } : { size: "large" })
26+
}
2027

2128

2229
//// [spreadDuplicate.js]
@@ -41,6 +48,7 @@ var a2 = __assign({ a: 123 }, (t ? a : {})); // string | number
4148
var b2 = __assign({ a: 123 }, (t ? b : {})); // string | number
4249
var c2 = __assign({ a: 123 }, (t ? c : {})); // string | number
4350
var d2 = __assign({ a: 123 }, (t ? d : {})); // string | number
51+
var example = __assign({ color: "red" }, (conditional ? { color: "green" } : { size: "large" }));
4452

4553

4654
//// [spreadDuplicate.d.ts]
@@ -81,3 +89,10 @@ declare let c2: {
8189
declare let d2: {
8290
a: string | number;
8391
};
92+
declare const conditional: boolean;
93+
declare const example: {
94+
color: string;
95+
} | {
96+
size: string;
97+
color: string;
98+
};

tests/baselines/reference/spreadDuplicate.symbols

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,19 @@ let d2 = { a: 123, ...(t ? d : {}) }; // string | number
6464
>t : Symbol(t, Decl(spreadDuplicate.ts, 7, 11))
6565
>d : Symbol(d, Decl(spreadDuplicate.ts, 5, 11))
6666

67+
// from #46463
68+
declare const conditional: boolean;
69+
>conditional : Symbol(conditional, Decl(spreadDuplicate.ts, 20, 13))
70+
71+
const example = {
72+
>example : Symbol(example, Decl(spreadDuplicate.ts, 21, 5))
73+
74+
color: "red", // OK
75+
>color : Symbol(color, Decl(spreadDuplicate.ts, 21, 17))
76+
77+
...(conditional ? { color: "green" } : { size: "large" })
78+
>conditional : Symbol(conditional, Decl(spreadDuplicate.ts, 20, 13))
79+
>color : Symbol(color, Decl(spreadDuplicate.ts, 23, 23))
80+
>size : Symbol(size, Decl(spreadDuplicate.ts, 23, 44))
81+
}
82+

tests/baselines/reference/spreadDuplicate.types

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,27 @@ let d2 = { a: 123, ...(t ? d : {}) }; // string | number
9292
>d : { a?: string | undefined; }
9393
>{} : {}
9494

95+
// from #46463
96+
declare const conditional: boolean;
97+
>conditional : boolean
98+
99+
const example = {
100+
>example : { color: string; } | { size: string; color: string; }
101+
>{ color: "red", // OK ...(conditional ? { color: "green" } : { size: "large" })} : { color: string; } | { size: string; color: string; }
102+
103+
color: "red", // OK
104+
>color : string
105+
>"red" : "red"
106+
107+
...(conditional ? { color: "green" } : { size: "large" })
108+
>(conditional ? { color: "green" } : { size: "large" }) : { color: string; } | { size: string; }
109+
>conditional ? { color: "green" } : { size: "large" } : { color: string; } | { size: string; }
110+
>conditional : boolean
111+
>{ color: "green" } : { color: string; }
112+
>color : string
113+
>"green" : "green"
114+
>{ size: "large" } : { size: string; }
115+
>size : string
116+
>"large" : "large"
117+
}
118+

tests/baselines/reference/spreadDuplicateExact.errors.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
tests/cases/conformance/types/spread/spreadDuplicateExact.ts(10,12): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
22
tests/cases/conformance/types/spread/spreadDuplicateExact.ts(12,12): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
3+
tests/cases/conformance/types/spread/spreadDuplicateExact.ts(23,5): error TS2783: 'color' is specified more than once, so this usage will be overwritten.
34

45

5-
==== tests/cases/conformance/types/spread/spreadDuplicateExact.ts (2 errors) ====
6+
==== tests/cases/conformance/types/spread/spreadDuplicateExact.ts (3 errors) ====
67
// Repro from #44438
78

89
declare let a: { a: string };
@@ -27,4 +28,14 @@ tests/cases/conformance/types/spread/spreadDuplicateExact.ts(12,12): error TS278
2728
let b2 = { a: 123, ...(t ? b : {}) }; // string | number
2829
let c2 = { a: 123, ...(t ? c : {}) }; // string | number | undefined
2930
let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined
31+
32+
// from #46463
33+
declare const conditional: boolean;
34+
const example = {
35+
color: "red", // error
36+
~~~~~~~~~~~~
37+
!!! error TS2783: 'color' is specified more than once, so this usage will be overwritten.
38+
!!! related TS2785 tests/cases/conformance/types/spread/spreadDuplicateExact.ts:24:5: This spread always overwrites this property.
39+
...(conditional ? { color: "green" } : { size: "large" })
40+
}
3041

tests/baselines/reference/spreadDuplicateExact.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ let a2 = { a: 123, ...(t ? a : {}) }; // string | number
1717
let b2 = { a: 123, ...(t ? b : {}) }; // string | number
1818
let c2 = { a: 123, ...(t ? c : {}) }; // string | number | undefined
1919
let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined
20+
21+
// from #46463
22+
declare const conditional: boolean;
23+
const example = {
24+
color: "red", // error
25+
...(conditional ? { color: "green" } : { size: "large" })
26+
}
2027

2128

2229
//// [spreadDuplicateExact.js]
@@ -41,6 +48,7 @@ var a2 = __assign({ a: 123 }, (t ? a : {})); // string | number
4148
var b2 = __assign({ a: 123 }, (t ? b : {})); // string | number
4249
var c2 = __assign({ a: 123 }, (t ? c : {})); // string | number | undefined
4350
var d2 = __assign({ a: 123 }, (t ? d : {})); // string | number | undefined
51+
var example = __assign({ color: "red" }, (conditional ? { color: "green" } : { size: "large" }));
4452

4553

4654
//// [spreadDuplicateExact.d.ts]
@@ -81,3 +89,10 @@ declare let c2: {
8189
declare let d2: {
8290
a: string | number | undefined;
8391
};
92+
declare const conditional: boolean;
93+
declare const example: {
94+
color: string;
95+
} | {
96+
size: string;
97+
color: string;
98+
};

tests/baselines/reference/spreadDuplicateExact.symbols

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,19 @@ let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined
6464
>t : Symbol(t, Decl(spreadDuplicateExact.ts, 7, 11))
6565
>d : Symbol(d, Decl(spreadDuplicateExact.ts, 5, 11))
6666

67+
// from #46463
68+
declare const conditional: boolean;
69+
>conditional : Symbol(conditional, Decl(spreadDuplicateExact.ts, 20, 13))
70+
71+
const example = {
72+
>example : Symbol(example, Decl(spreadDuplicateExact.ts, 21, 5))
73+
74+
color: "red", // error
75+
>color : Symbol(color, Decl(spreadDuplicateExact.ts, 21, 17))
76+
77+
...(conditional ? { color: "green" } : { size: "large" })
78+
>conditional : Symbol(conditional, Decl(spreadDuplicateExact.ts, 20, 13))
79+
>color : Symbol(color, Decl(spreadDuplicateExact.ts, 23, 23))
80+
>size : Symbol(size, Decl(spreadDuplicateExact.ts, 23, 44))
81+
}
82+

tests/baselines/reference/spreadDuplicateExact.types

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,27 @@ let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined
9292
>d : { a?: string | undefined; }
9393
>{} : {}
9494

95+
// from #46463
96+
declare const conditional: boolean;
97+
>conditional : boolean
98+
99+
const example = {
100+
>example : { color: string; } | { size: string; color: string; }
101+
>{ color: "red", // error ...(conditional ? { color: "green" } : { size: "large" })} : { color: string; } | { size: string; color: string; }
102+
103+
color: "red", // error
104+
>color : string
105+
>"red" : "red"
106+
107+
...(conditional ? { color: "green" } : { size: "large" })
108+
>(conditional ? { color: "green" } : { size: "large" }) : { color: string; } | { size: string; }
109+
>conditional ? { color: "green" } : { size: "large" } : { color: string; } | { size: string; }
110+
>conditional : boolean
111+
>{ color: "green" } : { color: string; }
112+
>color : string
113+
>"green" : "green"
114+
>{ size: "large" } : { size: string; }
115+
>size : string
116+
>"large" : "large"
117+
}
118+

tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(3,17): error TS2783: 'b' is specified more than once, so this usage will be overwritten.
2-
tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(9,14): error TS2783: 'x' is specified more than once, so this usage will be overwritten.
32
tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(15,14): error TS2783: 'x' is specified more than once, so this usage will be overwritten.
43
tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(24,14): error TS2783: 'command' is specified more than once, so this usage will be overwritten.
54
tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(28,14): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
65

76

8-
==== tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts (5 errors) ====
7+
==== tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts (4 errors) ====
98
declare var ab: { a: number, b: number };
109
declare var abq: { a: number, b?: number };
1110
var unused1 = { b: 1, ...ab } // error
@@ -18,9 +17,6 @@ tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(28,14): e
1817
var unused5 = { ...abq, b: 1 } // ok
1918
function g(obj: { x: number | undefined }) {
2019
return { x: 1, ...obj }; // ok, obj might have x: undefined
21-
~~~~
22-
!!! error TS2783: 'x' is specified more than once, so this usage will be overwritten.
23-
!!! related TS2785 tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts:9:20: This spread always overwrites this property.
2420
}
2521
function f(obj: { x: number } | undefined) {
2622
return { x: 1, ...obj }; // ok, obj might be undefined

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,10 @@ let a2 = { a: 123, ...(t ? a : {}) }; // string | number
1919
let b2 = { a: 123, ...(t ? b : {}) }; // string | number
2020
let c2 = { a: 123, ...(t ? c : {}) }; // string | number
2121
let d2 = { a: 123, ...(t ? d : {}) }; // string | number
22+
23+
// from #46463
24+
declare const conditional: boolean;
25+
const example = {
26+
color: "red", // OK
27+
...(conditional ? { color: "green" } : { size: "large" })
28+
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,10 @@ let a2 = { a: 123, ...(t ? a : {}) }; // string | number
2020
let b2 = { a: 123, ...(t ? b : {}) }; // string | number
2121
let c2 = { a: 123, ...(t ? c : {}) }; // string | number | undefined
2222
let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined
23+
24+
// from #46463
25+
declare const conditional: boolean;
26+
const example = {
27+
color: "red", // error
28+
...(conditional ? { color: "green" } : { size: "large" })
29+
}

0 commit comments

Comments
 (0)