From f1eb9898fba3a7a52739fdc1a0119e77ad9c5331 Mon Sep 17 00:00:00 2001 From: Alexander T Date: Tue, 17 Mar 2020 22:13:38 +0200 Subject: [PATCH] feat(36908): add 'property overwritten by spread' error for jsx attributes. add related span for conflicting declaration in spread (#37329) --- src/compiler/checker.ts | 33 +++--- src/compiler/diagnosticMessages.json | 4 + ...SpreadOverwritesAttributeStrict.errors.txt | 62 ++++++++++ .../jsxSpreadOverwritesAttributeStrict.js | 39 +++++++ ...jsxSpreadOverwritesAttributeStrict.symbols | 86 ++++++++++++++ .../jsxSpreadOverwritesAttributeStrict.types | 106 ++++++++++++++++++ .../reference/objectSpreadNegative.errors.txt | 13 ++- .../objectSpreadSetonlyAccessor.errors.txt | 1 + .../spreadOverwritesPropertyStrict.errors.txt | 3 + .../jsxSpreadOverwritesAttributeStrict.tsx | 29 +++++ 10 files changed, 362 insertions(+), 14 deletions(-) create mode 100644 tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.errors.txt create mode 100644 tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.js create mode 100644 tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.symbols create mode 100644 tests/baselines/reference/jsxSpreadOverwritesAttributeStrict.types create mode 100644 tests/cases/conformance/jsx/jsxSpreadOverwritesAttributeStrict.tsx 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 = ;