Make spread overwrite error more lenient.

Fixes #46463, but I don't thik it's a good fix. See
https://github.com/microsoft/TypeScript/issues/46463#issuecomment-1033956377
for discussion.
This commit is contained in:
Nathan Shively-Sanders
2022-02-09 08:32:35 -08:00
parent 460908a478
commit cc005d1d72
12 changed files with 150 additions and 17 deletions
+5 -6
View File
@@ -27593,12 +27593,11 @@ namespace ts {
function checkSpreadPropOverrides(type: Type, props: SymbolTable, spread: SpreadAssignment | JsxSpreadAttribute) {
for (const right of getPropertiesOfType(type)) {
if (!(right.flags & SymbolFlags.Optional)) {
const left = props.get(right.escapedName);
if (left) {
const diagnostic = error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName));
addRelatedInfo(diagnostic, createDiagnosticForNode(spread, Diagnostics.This_spread_always_overwrites_this_property));
}
const rightType = getTypeOfSymbol(right);
const left = props.get(right.escapedName);
if (left && (exactOptionalPropertyTypes || !maybeTypeOfKind(rightType, TypeFlags.Nullable)) && !(right.flags & SymbolFlags.Optional)) {
const diagnostic = error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName));
addRelatedInfo(diagnostic, createDiagnosticForNode(spread, Diagnostics.This_spread_always_overwrites_this_property));
}
}
}
@@ -1,8 +1,7 @@
tests/cases/conformance/types/spread/spreadDuplicate.ts(10,12): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
tests/cases/conformance/types/spread/spreadDuplicate.ts(12,12): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
==== tests/cases/conformance/types/spread/spreadDuplicate.ts (2 errors) ====
==== tests/cases/conformance/types/spread/spreadDuplicate.ts (1 errors) ====
// Repro from #44438
declare let a: { a: string };
@@ -18,13 +17,17 @@ tests/cases/conformance/types/spread/spreadDuplicate.ts(12,12): error TS2783: 'a
!!! related TS2785 tests/cases/conformance/types/spread/spreadDuplicate.ts:10:20: This spread always overwrites this property.
let b1 = { a: 123, ...b }; // string | number
let c1 = { a: 123, ...c }; // string | undefined (Error)
~~~~~~
!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
!!! related TS2785 tests/cases/conformance/types/spread/spreadDuplicate.ts:12:20: This spread always overwrites this property.
let d1 = { a: 123, ...d }; // string | number
let a2 = { a: 123, ...(t ? a : {}) }; // string | number
let b2 = { a: 123, ...(t ? b : {}) }; // string | number
let c2 = { a: 123, ...(t ? c : {}) }; // string | number
let d2 = { a: 123, ...(t ? d : {}) }; // string | number
// from #46463
declare const conditional: boolean;
const example = {
color: "red", // OK
...(conditional ? { color: "green" } : { size: "large" })
}
@@ -17,6 +17,13 @@ let a2 = { a: 123, ...(t ? a : {}) }; // string | number
let b2 = { a: 123, ...(t ? b : {}) }; // string | number
let c2 = { a: 123, ...(t ? c : {}) }; // string | number
let d2 = { a: 123, ...(t ? d : {}) }; // string | number
// from #46463
declare const conditional: boolean;
const example = {
color: "red", // OK
...(conditional ? { color: "green" } : { size: "large" })
}
//// [spreadDuplicate.js]
@@ -41,6 +48,7 @@ var a2 = __assign({ a: 123 }, (t ? a : {})); // string | number
var b2 = __assign({ a: 123 }, (t ? b : {})); // string | number
var c2 = __assign({ a: 123 }, (t ? c : {})); // string | number
var d2 = __assign({ a: 123 }, (t ? d : {})); // string | number
var example = __assign({ color: "red" }, (conditional ? { color: "green" } : { size: "large" }));
//// [spreadDuplicate.d.ts]
@@ -81,3 +89,10 @@ declare let c2: {
declare let d2: {
a: string | number;
};
declare const conditional: boolean;
declare const example: {
color: string;
} | {
size: string;
color: string;
};
@@ -64,3 +64,19 @@ let d2 = { a: 123, ...(t ? d : {}) }; // string | number
>t : Symbol(t, Decl(spreadDuplicate.ts, 7, 11))
>d : Symbol(d, Decl(spreadDuplicate.ts, 5, 11))
// from #46463
declare const conditional: boolean;
>conditional : Symbol(conditional, Decl(spreadDuplicate.ts, 20, 13))
const example = {
>example : Symbol(example, Decl(spreadDuplicate.ts, 21, 5))
color: "red", // OK
>color : Symbol(color, Decl(spreadDuplicate.ts, 21, 17))
...(conditional ? { color: "green" } : { size: "large" })
>conditional : Symbol(conditional, Decl(spreadDuplicate.ts, 20, 13))
>color : Symbol(color, Decl(spreadDuplicate.ts, 23, 23))
>size : Symbol(size, Decl(spreadDuplicate.ts, 23, 44))
}
@@ -92,3 +92,27 @@ let d2 = { a: 123, ...(t ? d : {}) }; // string | number
>d : { a?: string | undefined; }
>{} : {}
// from #46463
declare const conditional: boolean;
>conditional : boolean
const example = {
>example : { color: string; } | { size: string; color: string; }
>{ color: "red", // OK ...(conditional ? { color: "green" } : { size: "large" })} : { color: string; } | { size: string; color: string; }
color: "red", // OK
>color : string
>"red" : "red"
...(conditional ? { color: "green" } : { size: "large" })
>(conditional ? { color: "green" } : { size: "large" }) : { color: string; } | { size: string; }
>conditional ? { color: "green" } : { size: "large" } : { color: string; } | { size: string; }
>conditional : boolean
>{ color: "green" } : { color: string; }
>color : string
>"green" : "green"
>{ size: "large" } : { size: string; }
>size : string
>"large" : "large"
}
@@ -1,8 +1,9 @@
tests/cases/conformance/types/spread/spreadDuplicateExact.ts(10,12): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
tests/cases/conformance/types/spread/spreadDuplicateExact.ts(12,12): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
tests/cases/conformance/types/spread/spreadDuplicateExact.ts(23,5): error TS2783: 'color' is specified more than once, so this usage will be overwritten.
==== tests/cases/conformance/types/spread/spreadDuplicateExact.ts (2 errors) ====
==== tests/cases/conformance/types/spread/spreadDuplicateExact.ts (3 errors) ====
// Repro from #44438
declare let a: { a: string };
@@ -27,4 +28,14 @@ tests/cases/conformance/types/spread/spreadDuplicateExact.ts(12,12): error TS278
let b2 = { a: 123, ...(t ? b : {}) }; // string | number
let c2 = { a: 123, ...(t ? c : {}) }; // string | number | undefined
let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined
// from #46463
declare const conditional: boolean;
const example = {
color: "red", // error
~~~~~~~~~~~~
!!! error TS2783: 'color' is specified more than once, so this usage will be overwritten.
!!! related TS2785 tests/cases/conformance/types/spread/spreadDuplicateExact.ts:24:5: This spread always overwrites this property.
...(conditional ? { color: "green" } : { size: "large" })
}
@@ -17,6 +17,13 @@ let a2 = { a: 123, ...(t ? a : {}) }; // string | number
let b2 = { a: 123, ...(t ? b : {}) }; // string | number
let c2 = { a: 123, ...(t ? c : {}) }; // string | number | undefined
let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined
// from #46463
declare const conditional: boolean;
const example = {
color: "red", // error
...(conditional ? { color: "green" } : { size: "large" })
}
//// [spreadDuplicateExact.js]
@@ -41,6 +48,7 @@ var a2 = __assign({ a: 123 }, (t ? a : {})); // string | number
var b2 = __assign({ a: 123 }, (t ? b : {})); // string | number
var c2 = __assign({ a: 123 }, (t ? c : {})); // string | number | undefined
var d2 = __assign({ a: 123 }, (t ? d : {})); // string | number | undefined
var example = __assign({ color: "red" }, (conditional ? { color: "green" } : { size: "large" }));
//// [spreadDuplicateExact.d.ts]
@@ -81,3 +89,10 @@ declare let c2: {
declare let d2: {
a: string | number | undefined;
};
declare const conditional: boolean;
declare const example: {
color: string;
} | {
size: string;
color: string;
};
@@ -64,3 +64,19 @@ let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined
>t : Symbol(t, Decl(spreadDuplicateExact.ts, 7, 11))
>d : Symbol(d, Decl(spreadDuplicateExact.ts, 5, 11))
// from #46463
declare const conditional: boolean;
>conditional : Symbol(conditional, Decl(spreadDuplicateExact.ts, 20, 13))
const example = {
>example : Symbol(example, Decl(spreadDuplicateExact.ts, 21, 5))
color: "red", // error
>color : Symbol(color, Decl(spreadDuplicateExact.ts, 21, 17))
...(conditional ? { color: "green" } : { size: "large" })
>conditional : Symbol(conditional, Decl(spreadDuplicateExact.ts, 20, 13))
>color : Symbol(color, Decl(spreadDuplicateExact.ts, 23, 23))
>size : Symbol(size, Decl(spreadDuplicateExact.ts, 23, 44))
}
@@ -92,3 +92,27 @@ let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined
>d : { a?: string | undefined; }
>{} : {}
// from #46463
declare const conditional: boolean;
>conditional : boolean
const example = {
>example : { color: string; } | { size: string; color: string; }
>{ color: "red", // error ...(conditional ? { color: "green" } : { size: "large" })} : { color: string; } | { size: string; color: string; }
color: "red", // error
>color : string
>"red" : "red"
...(conditional ? { color: "green" } : { size: "large" })
>(conditional ? { color: "green" } : { size: "large" }) : { color: string; } | { size: string; }
>conditional ? { color: "green" } : { size: "large" } : { color: string; } | { size: string; }
>conditional : boolean
>{ color: "green" } : { color: string; }
>color : string
>"green" : "green"
>{ size: "large" } : { size: string; }
>size : string
>"large" : "large"
}
@@ -1,11 +1,10 @@
tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(3,17): error TS2783: 'b' is specified more than once, so this usage will be overwritten.
tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(9,14): error TS2783: 'x' is specified more than once, so this usage will be overwritten.
tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(15,14): error TS2783: 'x' is specified more than once, so this usage will be overwritten.
tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(24,14): error TS2783: 'command' is specified more than once, so this usage will be overwritten.
tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(28,14): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
==== tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts (5 errors) ====
==== tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts (4 errors) ====
declare var ab: { a: number, b: number };
declare var abq: { a: number, b?: number };
var unused1 = { b: 1, ...ab } // error
@@ -18,9 +17,6 @@ tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(28,14): e
var unused5 = { ...abq, b: 1 } // ok
function g(obj: { x: number | undefined }) {
return { x: 1, ...obj }; // ok, obj might have x: undefined
~~~~
!!! error TS2783: 'x' is specified more than once, so this usage will be overwritten.
!!! related TS2785 tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts:9:20: This spread always overwrites this property.
}
function f(obj: { x: number } | undefined) {
return { x: 1, ...obj }; // ok, obj might be undefined
@@ -19,3 +19,10 @@ let a2 = { a: 123, ...(t ? a : {}) }; // string | number
let b2 = { a: 123, ...(t ? b : {}) }; // string | number
let c2 = { a: 123, ...(t ? c : {}) }; // string | number
let d2 = { a: 123, ...(t ? d : {}) }; // string | number
// from #46463
declare const conditional: boolean;
const example = {
color: "red", // OK
...(conditional ? { color: "green" } : { size: "large" })
}
@@ -20,3 +20,10 @@ let a2 = { a: 123, ...(t ? a : {}) }; // string | number
let b2 = { a: 123, ...(t ? b : {}) }; // string | number
let c2 = { a: 123, ...(t ? c : {}) }; // string | number | undefined
let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined
// from #46463
declare const conditional: boolean;
const example = {
color: "red", // error
...(conditional ? { color: "green" } : { size: "large" })
}