diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 7530f58d268..1bd276310e7 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -22684,8 +22684,8 @@ namespace ts {
// Grammar checking
checkGrammarObjectLiteralExpression(node, inDestructuringPattern);
- let propertiesTable: SymbolTable;
- const allPropertiesTable = createSymbolTable();
+ const allPropertiesTable = strictNullChecks ? createSymbolTable() : undefined;
+ let propertiesTable = createSymbolTable();
let propertiesArray: Symbol[] = [];
let spread: Type = emptyObjectType;
@@ -22701,7 +22701,6 @@ namespace ts {
let patternWithComputedProperties = false;
let hasComputedStringProperty = false;
let hasComputedNumberProperty = false;
- propertiesTable = createSymbolTable();
let offset = 0;
for (let i = 0; i < node.properties.length; i++) {
@@ -22767,7 +22766,7 @@ namespace ts {
prop.type = type;
prop.target = member;
member = prop;
- allPropertiesTable.set(prop.escapedName, prop);
+ allPropertiesTable?.set(prop.escapedName, prop);
}
else if (memberDecl.kind === SyntaxKind.SpreadAssignment) {
if (languageVersion < ScriptTarget.ES2015) {
@@ -22785,16 +22784,9 @@ namespace ts {
error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types);
return errorType;
}
- for (const right of getPropertiesOfType(type)) {
- const rightType = getTypeOfSymbol(right);
- const left = allPropertiesTable.get(right.escapedName);
- if (strictNullChecks &&
- left &&
- !maybeTypeOfKind(rightType, TypeFlags.Nullable)) {
- error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName));
- }
+ if (allPropertiesTable) {
+ checkSpreadPropOverrides(type, allPropertiesTable, memberDecl);
}
-
spread = getSpreadType(spread, type, node.symbol, objectFlags, inConstContext);
offset = i + 1;
continue;
@@ -22965,6 +22957,7 @@ namespace ts {
*/
function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, checkMode: CheckMode | undefined) {
const attributes = openingLikeElement.attributes;
+ const allAttributesTable = strictNullChecks ? createSymbolTable() : undefined;
let attributesTable = createSymbolTable();
let spread: Type = emptyJsxObjectType;
let hasSpreadAnyType = false;
@@ -22988,6 +22981,7 @@ namespace ts {
attributeSymbol.type = exprType;
attributeSymbol.target = member;
attributesTable.set(attributeSymbol.escapedName, attributeSymbol);
+ allAttributesTable?.set(attributeSymbol.escapedName, attributeSymbol);
if (attributeDecl.name.escapedText === jsxChildrenPropertyName) {
explicitlySpecifyChildrenAttribute = true;
}
@@ -23004,6 +22998,9 @@ namespace ts {
}
if (isValidSpreadType(exprType)) {
spread = getSpreadType(spread, exprType, attributes.symbol, objectFlags, /*readonly*/ false);
+ if (allAttributesTable) {
+ checkSpreadPropOverrides(exprType, allAttributesTable, attributeDecl);
+ }
}
else {
typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType;
@@ -23088,6 +23085,16 @@ namespace ts {
return childrenTypes;
}
+ function checkSpreadPropOverrides(type: Type, props: SymbolTable, spread: SpreadAssignment | JsxSpreadAttribute) {
+ for (const right of getPropertiesOfType(type)) {
+ const left = props.get(right.escapedName);
+ if (left && !maybeTypeOfKind(getTypeOfSymbol(right), TypeFlags.Nullable)) {
+ 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));
+ }
+ }
+ }
+
/**
* Check attributes property of opening-like element. This function is called during chooseOverload to get call signature of a JSX opening-like element.
* (See "checkApplicableSignatureForJsxOpeningLikeElement" for how the function is used)
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index 96144c02d77..a9f531c901c 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -2907,6 +2907,10 @@
"category": "Error",
"code": 2784
},
+ "This spread always overwrites this property.": {
+ "category": "Error",
+ "code": 2785
+ },
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
diff --git a/tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.errors.txt b/tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.errors.txt
new file mode 100644
index 00000000000..fefbc6cac4d
--- /dev/null
+++ b/tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.errors.txt
@@ -0,0 +1,62 @@
+error TS2318: Cannot find global type 'CallableFunction'.
+error TS2318: Cannot find global type 'NewableFunction'.
+tests/cases/conformance/jsx/file.tsx(19,17): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
+tests/cases/conformance/jsx/file.tsx(20,17): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
+tests/cases/conformance/jsx/file.tsx(20,23): error TS2783: 'b' is specified more than once, so this usage will be overwritten.
+tests/cases/conformance/jsx/file.tsx(21,17): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
+tests/cases/conformance/jsx/file.tsx(21,23): error TS2783: 'd' is specified more than once, so this usage will be overwritten.
+tests/cases/conformance/jsx/file.tsx(22,17): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
+tests/cases/conformance/jsx/file.tsx(22,17): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
+tests/cases/conformance/jsx/file.tsx(22,23): error TS2783: 'd' is specified more than once, so this usage will be overwritten.
+
+
+!!! error TS2318: Cannot find global type 'CallableFunction'.
+!!! error TS2318: Cannot find global type 'NewableFunction'.
+==== tests/cases/conformance/jsx/file.tsx (8 errors) ====
+ import React = require('react');
+
+ interface Props {
+ a: number;
+ b: number;
+ c?: number;
+ d?: number;
+ }
+
+
+ const props: Props = { a: 1, b: 1 };
+ const Foo = (props: Props) =>
{ props.a }
;
+
+ // ok
+ const a1 = ;
+ const a2 = ;
+
+ // error
+ const b1 = ;
+ ~~~~~
+!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/jsx/file.tsx:19:23: This spread always overwrites this property.
+ const b2 = ;
+ ~~~~~
+!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/jsx/file.tsx:20:29: This spread always overwrites this property.
+ ~~~~~
+!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/jsx/file.tsx:20:29: This spread always overwrites this property.
+ const b3 = ;
+ ~~~~~
+!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/jsx/file.tsx:21:29: This spread always overwrites this property.
+ ~~~~~
+!!! error TS2783: 'd' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/jsx/file.tsx:21:40: This spread always overwrites this property.
+ const b4 = ;
+ ~~~~~
+!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/jsx/file.tsx:22:29: This spread always overwrites this property.
+ ~~~~~
+!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/jsx/file.tsx:22:40: This spread always overwrites this property.
+ ~~~~~
+!!! error TS2783: 'd' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/jsx/file.tsx:22:40: This spread always overwrites this property.
+
\ No newline at end of file
diff --git a/tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.js b/tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.js
new file mode 100644
index 00000000000..8d7e5dd549a
--- /dev/null
+++ b/tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.js
@@ -0,0 +1,39 @@
+//// [file.tsx]
+import React = require('react');
+
+interface Props {
+ a: number;
+ b: number;
+ c?: number;
+ d?: number;
+}
+
+
+const props: Props = { a: 1, b: 1 };
+const Foo = (props: Props) => { props.a }
;
+
+// ok
+const a1 = ;
+const a2 = ;
+
+// error
+const b1 = ;
+const b2 = ;
+const b3 = ;
+const b4 = ;
+
+
+//// [file.jsx]
+"use strict";
+exports.__esModule = true;
+var React = require("react");
+var props = { a: 1, b: 1 };
+var Foo = function (props) { return {props.a}
; };
+// ok
+var a1 = ;
+var a2 = ;
+// error
+var b1 = ;
+var b2 = ;
+var b3 = ;
+var b4 = ;
diff --git a/tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.symbols b/tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.symbols
new file mode 100644
index 00000000000..0c0e4e74341
--- /dev/null
+++ b/tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.symbols
@@ -0,0 +1,86 @@
+=== tests/cases/conformance/jsx/file.tsx ===
+import React = require('react');
+>React : Symbol(React, Decl(file.tsx, 0, 0))
+
+interface Props {
+>Props : Symbol(Props, Decl(file.tsx, 0, 32))
+
+ a: number;
+>a : Symbol(Props.a, Decl(file.tsx, 2, 17))
+
+ b: number;
+>b : Symbol(Props.b, Decl(file.tsx, 3, 14))
+
+ c?: number;
+>c : Symbol(Props.c, Decl(file.tsx, 4, 14))
+
+ d?: number;
+>d : Symbol(Props.d, Decl(file.tsx, 5, 15))
+}
+
+
+const props: Props = { a: 1, b: 1 };
+>props : Symbol(props, Decl(file.tsx, 10, 5))
+>Props : Symbol(Props, Decl(file.tsx, 0, 32))
+>a : Symbol(a, Decl(file.tsx, 10, 22))
+>b : Symbol(b, Decl(file.tsx, 10, 28))
+
+const Foo = (props: Props) => { props.a }
;
+>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
+>props : Symbol(props, Decl(file.tsx, 11, 13))
+>Props : Symbol(Props, Decl(file.tsx, 0, 32))
+>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
+>props.a : Symbol(Props.a, Decl(file.tsx, 2, 17))
+>props : Symbol(props, Decl(file.tsx, 11, 13))
+>a : Symbol(Props.a, Decl(file.tsx, 2, 17))
+>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
+
+// ok
+const a1 = ;
+>a1 : Symbol(a1, Decl(file.tsx, 14, 5))
+>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
+>props : Symbol(props, Decl(file.tsx, 10, 5))
+>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
+
+const a2 = ;
+>a2 : Symbol(a2, Decl(file.tsx, 15, 5))
+>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
+>d : Symbol(d, Decl(file.tsx, 15, 15))
+>props : Symbol(props, Decl(file.tsx, 10, 5))
+>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
+
+// error
+const b1 = ;
+>b1 : Symbol(b1, Decl(file.tsx, 18, 5))
+>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
+>a : Symbol(a, Decl(file.tsx, 18, 15))
+>props : Symbol(props, Decl(file.tsx, 10, 5))
+>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
+
+const b2 = ;
+>b2 : Symbol(b2, Decl(file.tsx, 19, 5))
+>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
+>a : Symbol(a, Decl(file.tsx, 19, 15))
+>b : Symbol(b, Decl(file.tsx, 19, 21))
+>props : Symbol(props, Decl(file.tsx, 10, 5))
+>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
+
+const b3 = ;
+>b3 : Symbol(b3, Decl(file.tsx, 20, 5))
+>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
+>a : Symbol(a, Decl(file.tsx, 20, 15))
+>d : Symbol(d, Decl(file.tsx, 20, 21))
+>props : Symbol(props, Decl(file.tsx, 10, 5))
+>d : Symbol(d, Decl(file.tsx, 20, 44))
+>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
+
+const b4 = ;
+>b4 : Symbol(b4, Decl(file.tsx, 21, 5))
+>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
+>a : Symbol(a, Decl(file.tsx, 21, 15))
+>d : Symbol(d, Decl(file.tsx, 21, 21))
+>props : Symbol(props, Decl(file.tsx, 10, 5))
+>a : Symbol(a, Decl(file.tsx, 21, 44))
+>d : Symbol(d, Decl(file.tsx, 21, 50))
+>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
+
diff --git a/tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.types b/tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.types
new file mode 100644
index 00000000000..37eca94cbcc
--- /dev/null
+++ b/tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.types
@@ -0,0 +1,106 @@
+=== tests/cases/conformance/jsx/file.tsx ===
+import React = require('react');
+>React : typeof React
+
+interface Props {
+ a: number;
+>a : number
+
+ b: number;
+>b : number
+
+ c?: number;
+>c : number | undefined
+
+ d?: number;
+>d : number | undefined
+}
+
+
+const props: Props = { a: 1, b: 1 };
+>props : Props
+>{ a: 1, b: 1 } : { a: number; b: number; }
+>a : number
+>1 : 1
+>b : number
+>1 : 1
+
+const Foo = (props: Props) => { props.a }
;
+>Foo : (props: Props) => JSX.Element
+>(props: Props) => { props.a }
: (props: Props) => JSX.Element
+>props : Props
+>{ props.a }
: JSX.Element
+>div : any
+>props.a : number
+>props : Props
+>a : number
+>div : any
+
+// ok
+const a1 = ;
+>a1 : JSX.Element
+> : JSX.Element
+>Foo : (props: Props) => JSX.Element
+>props : Props
+>Foo : (props: Props) => JSX.Element
+
+const a2 = ;
+>a2 : JSX.Element
+> : JSX.Element
+>Foo : (props: Props) => JSX.Element
+>d : number
+>1 : 1
+>props : Props
+>Foo : (props: Props) => JSX.Element
+
+// error
+const b1 = ;
+>b1 : JSX.Element
+> : JSX.Element
+>Foo : (props: Props) => JSX.Element
+>a : number
+>1 : 1
+>props : Props
+>Foo : (props: Props) => JSX.Element
+
+const b2 = ;
+>b2 : JSX.Element
+> : JSX.Element
+>Foo : (props: Props) => JSX.Element
+>a : number
+>1 : 1
+>b : number
+>2 : 2
+>props : Props
+>Foo : (props: Props) => JSX.Element
+
+const b3 = ;
+>b3 : JSX.Element
+> : JSX.Element
+>Foo : (props: Props) => JSX.Element
+>a : number
+>1 : 1
+>d : number
+>1 : 1
+>props : Props
+>{ d: 1 } : { d: number; }
+>d : number
+>1 : 1
+>Foo : (props: Props) => JSX.Element
+
+const b4 = ;
+>b4 : JSX.Element
+> : JSX.Element
+>Foo : (props: Props) => JSX.Element
+>a : number
+>1 : 1
+>d : number
+>1 : 1
+>props : Props
+>{ a: 1, d: 1 } : { a: number; d: number; }
+>a : number
+>1 : 1
+>d : number
+>1 : 1
+>Foo : (props: Props) => JSX.Element
+
diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt
index 8b0ae9abbc5..397e7e134e0 100644
--- a/tests/baselines/reference/objectSpreadNegative.errors.txt
+++ b/tests/baselines/reference/objectSpreadNegative.errors.txt
@@ -10,6 +10,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,36): error TS230
tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,53): error TS2300: Duplicate identifier 'b'.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,7): error TS2783: 'b' is specified more than once, so this usage will be overwritten.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,7): error TS2783: 'b' is specified more than once, so this usage will be overwritten.
+tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,7): error TS2783: 'b' is specified more than once, so this usage will be overwritten.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(39,14): error TS2783: 'b' is specified more than once, so this usage will be overwritten.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(41,53): error TS2783: 'd' is specified more than once, so this usage will be overwritten.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(43,7): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
@@ -26,7 +27,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(69,9): error TS2339
tests/cases/conformance/types/spread/objectSpreadNegative.ts(74,11): error TS2339: Property 'a' does not exist on type '{}'.
-==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (22 errors) ====
+==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (23 errors) ====
let o = { a: 1, b: 'no' }
/// private propagates
@@ -70,6 +71,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(74,11): error TS233
let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' }
~~~~~~~~
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:28:30: This spread always overwrites this property.
~
!!! error TS2300: Duplicate identifier 'b'.
~
@@ -80,6 +82,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(74,11): error TS233
{ b: 'ignored', ...o }
~~~~~~~~~~~~
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:32:21: This spread always overwrites this property.
let o3 = { a: 1, b: 'no' }
let o4 = { b: 'yes', c: true }
@@ -87,22 +90,30 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(74,11): error TS233
{ b: 'ok', ...o3, ...o4 }
~~~~~~~
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:37:16: This spread always overwrites this property.
+ ~~~~~~~
+!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:37:23: This spread always overwrites this property.
let combinedMid: { a: number, b: string, c: boolean } =
{ ...o3, b: 'ok', ...o4 }
~~~~~~~
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:39:23: This spread always overwrites this property.
let combinedNested: { a: number, b: boolean, c: string, d: string } =
{ ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } }
~~~~~~~~~~~~~~~~~
!!! error TS2783: 'd' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:41:72: This spread always overwrites this property.
let changeTypeBefore: { a: number, b: string } =
{ a: 'wrong type?', ...o3 };
~~~~~~~~~~~~~~~~
!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:43:25: This spread always overwrites this property.
let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } =
{ ...o3, ['in the middle']: 13, b: 'maybe?', ...o4 }
~~~~~~~~~~~
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:45:50: This spread always overwrites this property.
// primitives are not allowed, except for falsy ones
let spreadNum = { ...12 };
diff --git a/tests/baselines/reference/objectSpreadSetonlyAccessor.errors.txt b/tests/baselines/reference/objectSpreadSetonlyAccessor.errors.txt
index cb3eb23d972..bbf419d6b7a 100644
--- a/tests/baselines/reference/objectSpreadSetonlyAccessor.errors.txt
+++ b/tests/baselines/reference/objectSpreadSetonlyAccessor.errors.txt
@@ -6,4 +6,5 @@ tests/cases/conformance/types/spread/objectSpreadSetonlyAccessor.ts(2,34): error
const o2: { foo: undefined } = { foo: 1, ... { set foo(_v: number) { } } }
~~~~~~
!!! error TS2783: 'foo' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadSetonlyAccessor.ts:2:42: This spread always overwrites this property.
\ No newline at end of file
diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt b/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt
index be9054dfc51..b671a9ca73d 100644
--- a/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt
+++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt
@@ -9,6 +9,7 @@ tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(24,14): e
var unused1 = { b: 1, ...ab } // error
~~~~
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts:3:23: This spread always overwrites this property.
var unused2 = { ...ab, ...ab } // ok, overwritten error doesn't apply to spreads
var unused3 = { b: 1, ...abq } // ok, abq might have b: undefined
var unused4 = { ...ab, b: 1 } // ok, we don't care that b in ab is overwritten
@@ -23,6 +24,7 @@ tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(24,14): e
return { x: 1, ...obj } // error
~~~~
!!! error TS2783: 'x' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts:15:20: This spread always overwrites this property.
}
function i(b: boolean, t: { command: string, ok: string }) {
return { command: "hi", ...(b ? t : {}) } // ok
@@ -34,5 +36,6 @@ tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(24,14): e
return { command: "hi", ...{ spoiler: true }, spoiler2: true, ...t } // error
~~~~~~~~~~~~~
!!! error TS2783: 'command' is specified more than once, so this usage will be overwritten.
+!!! related TS2785 tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts:24:67: This spread always overwrites this property.
}
\ No newline at end of file
diff --git a/tests/cases/conformance/jsx/jsxSpreadOverwritesAttributeStrict.tsx b/tests/cases/conformance/jsx/jsxSpreadOverwritesAttributeStrict.tsx
new file mode 100644
index 00000000000..1b7d7133a54
--- /dev/null
+++ b/tests/cases/conformance/jsx/jsxSpreadOverwritesAttributeStrict.tsx
@@ -0,0 +1,29 @@
+// @filename: file.tsx
+// @jsx: preserve
+// @strict: true
+// @noLib: true
+// @skipLibCheck: true
+// @libFiles: react.d.ts,lib.d.ts
+
+import React = require('react');
+
+interface Props {
+ a: number;
+ b: number;
+ c?: number;
+ d?: number;
+}
+
+
+const props: Props = { a: 1, b: 1 };
+const Foo = (props: Props) => { props.a }
;
+
+// ok
+const a1 = ;
+const a2 = ;
+
+// error
+const b1 = ;
+const b2 = ;
+const b3 = ;
+const b4 = ;