From b5fc5c0ed84adf5a00741906c247533f4a4245ca Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 9 Oct 2018 15:11:21 -0700 Subject: [PATCH 1/2] Error: Property is overwritten by later spread Move the checking from JSX to getSpreadType so that normal objects get the error too. Also reword the missing semicolon related error to be less silly. --- src/compiler/checker.ts | 26 +- src/compiler/diagnosticMessages.json | 6 +- ...CallingTypeAssertionExpressions.errors.txt | 6 +- .../checkJsxChildrenProperty13.errors.txt | 6 +- .../checkJsxChildrenProperty2.errors.txt | 6 +- .../excessPropertyCheckWithSpread.errors.txt | 30 -- tests/baselines/reference/objectSpread.js | 24 +- .../baselines/reference/objectSpread.symbols | 436 ++++++++---------- tests/baselines/reference/objectSpread.types | 91 ---- .../reference/objectSpreadNegative.errors.txt | 66 ++- .../reference/objectSpreadNegative.js | 28 +- .../reference/objectSpreadNegative.symbols | 257 +++++++---- .../reference/objectSpreadNegative.types | 108 ++++- .../spreadOverwritesProperty.errors.txt | 12 + .../reference/spreadOverwritesProperty.js | 23 + .../spreadOverwritesProperty.symbols | 26 ++ .../reference/spreadOverwritesProperty.types | 31 ++ .../spreadOverwritesPropertyStrict.errors.txt | 12 + .../spreadOverwritesPropertyStrict.js | 24 + .../spreadOverwritesPropertyStrict.symbols | 26 ++ .../spreadOverwritesPropertyStrict.types | 31 ++ .../reference/spreadUnion3.errors.txt | 5 +- .../conformance/types/spread/objectSpread.ts | 13 - .../types/spread/objectSpreadNegative.ts | 17 +- .../types/spread/spreadOverwritesProperty.ts | 5 + .../spread/spreadOverwritesPropertyStrict.ts | 6 + 26 files changed, 776 insertions(+), 545 deletions(-) delete mode 100644 tests/baselines/reference/excessPropertyCheckWithSpread.errors.txt create mode 100644 tests/baselines/reference/spreadOverwritesProperty.errors.txt create mode 100644 tests/baselines/reference/spreadOverwritesProperty.js create mode 100644 tests/baselines/reference/spreadOverwritesProperty.symbols create mode 100644 tests/baselines/reference/spreadOverwritesProperty.types create mode 100644 tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt create mode 100644 tests/baselines/reference/spreadOverwritesPropertyStrict.js create mode 100644 tests/baselines/reference/spreadOverwritesPropertyStrict.symbols create mode 100644 tests/baselines/reference/spreadOverwritesPropertyStrict.types create mode 100644 tests/cases/conformance/types/spread/spreadOverwritesProperty.ts create mode 100644 tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fe2ce42652af4..ad283d7b3eb1b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9861,6 +9861,9 @@ namespace ts { result.nameType = leftProp.nameType; members.set(leftProp.escapedName, result); } + else if (symbol && shouldCheckAsExcessProperty(leftProp, symbol) && !shouldCheckAsExcessProperty(rightProp, symbol)) { + error(leftProp.valueDeclaration, Diagnostics._0_is_overwritten_by_a_later_spread, unescapeLeadingUnderscores(leftProp.escapedName)); + } } else { members.set(leftProp.escapedName, getNonReadonlySymbol(leftProp)); @@ -11547,7 +11550,7 @@ namespace ts { return hasExcessProperties(source, discriminant, /*discriminant*/ undefined, reportErrors); } for (const prop of getPropertiesOfObjectType(source)) { - if (!isPropertyFromSpread(prop, source.symbol) && !isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) { + if (shouldCheckAsExcessProperty(prop, source.symbol) && !isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) { if (reportErrors) { // We know *exactly* where things went wrong when comparing the types. // Use this property as the error node as this will be more helpful in @@ -11591,10 +11594,6 @@ namespace ts { return false; } - function isPropertyFromSpread(prop: Symbol, container: Symbol) { - return prop.valueDeclaration && container.valueDeclaration && prop.valueDeclaration.parent !== container.valueDeclaration; - } - function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType): Ternary { let result = Ternary.True; const sourceTypes = source.types; @@ -12507,6 +12506,10 @@ namespace ts { return match || defaultValue; } + function shouldCheckAsExcessProperty(prop: Symbol, container: Symbol) { + return prop.valueDeclaration && container.valueDeclaration && prop.valueDeclaration.parent === container.valueDeclaration; + } + /** * A type is 'weak' if it is an object type with at least one optional property * and no required properties, call/construct signatures or index signatures @@ -17632,7 +17635,6 @@ namespace ts { let spread: Type = emptyObjectType; let hasSpreadAnyType = false; let typeToIntersect: Type | undefined; - let explicitlySpecifyChildrenAttribute = false; let propagatingFlags: TypeFlags = 0; const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(openingLikeElement)); @@ -17651,9 +17653,6 @@ namespace ts { attributeSymbol.type = exprType; attributeSymbol.target = member; attributesTable.set(attributeSymbol.escapedName, attributeSymbol); - if (attributeDecl.name.escapedText === jsxChildrenPropertyName) { - explicitlySpecifyChildrenAttribute = true; - } } else { Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute); @@ -17687,13 +17686,6 @@ namespace ts { const childrenTypes: Type[] = checkJsxChildren(parent, checkMode); if (!hasSpreadAnyType && jsxChildrenPropertyName && jsxChildrenPropertyName !== "") { - // Error if there is a attribute named "children" explicitly specified and children element. - // This is because children element will overwrite the value from attributes. - // Note: we will not warn "children" attribute overwritten if "children" attribute is specified in object spread. - if (explicitlySpecifyChildrenAttribute) { - error(attributes, Diagnostics._0_are_specified_twice_The_attribute_named_0_will_be_overwritten, unescapeLeadingUnderscores(jsxChildrenPropertyName)); - } - const contextualType = getApparentTypeOfContextualType(openingLikeElement.attributes); const childrenContextualType = contextualType && getTypeOfPropertyOfContextualType(contextualType, jsxChildrenPropertyName); // If there are children in the body of JSX element, create dummy attribute "children" with the union of children types so that it will pass the attribute checking process @@ -20049,7 +20041,7 @@ namespace ts { if (node.arguments.length === 1 && isTypeAssertion(first(node.arguments))) { const text = getSourceFileOfNode(node).text; if (isLineBreak(text.charCodeAt(skipTrivia(text, node.expression.end, /* stopAfterLineBreak */ true) - 1))) { - relatedInformation = createDiagnosticForNode(node.expression, Diagnostics.It_is_highly_likely_that_you_are_missing_a_semicolon); + relatedInformation = createDiagnosticForNode(node.expression, Diagnostics.Are_you_missing_a_semicolon_here); } } invocationError(node, apparentType, SignatureKind.Call, relatedInformation); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 7baeeb7b65ddd..266e34465b205 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2489,10 +2489,14 @@ "category": "Error", "code": 2733 }, - "It is highly likely that you are missing a semicolon.": { + "Are you missing a semicolon here?": { "category": "Error", "code": 2734 }, + "'{0}' is overwritten by a later spread.": { + "category": "Error", + "code": 2735 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/betterErrorForAccidentallyCallingTypeAssertionExpressions.errors.txt b/tests/baselines/reference/betterErrorForAccidentallyCallingTypeAssertionExpressions.errors.txt index 023e40a70dad3..67e362623c830 100644 --- a/tests/baselines/reference/betterErrorForAccidentallyCallingTypeAssertionExpressions.errors.txt +++ b/tests/baselines/reference/betterErrorForAccidentallyCallingTypeAssertionExpressions.errors.txt @@ -21,19 +21,19 @@ tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.t (1 as number).toString(); ~~~~~~~~~~~~~ !!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures. -!!! related TS2734 tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts:7:1: It is highly likely that you are missing a semicolon. +!!! related TS2734 tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts:7:1: Are you missing a semicolon here? foo() ~~~~~~~~ (1 as number).toString(); ~~~~~~~~~~~~~~~~~ !!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures. -!!! related TS2734 tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts:10:1: It is highly likely that you are missing a semicolon. +!!! related TS2734 tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts:10:1: Are you missing a semicolon here? foo() ~~~~~~~~ (1).toString(); ~~~~~~~~~~~~~~~ !!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures. -!!! related TS2734 tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts:13:1: It is highly likely that you are missing a semicolon. +!!! related TS2734 tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts:13:1: Are you missing a semicolon here? \ No newline at end of file diff --git a/tests/baselines/reference/checkJsxChildrenProperty13.errors.txt b/tests/baselines/reference/checkJsxChildrenProperty13.errors.txt index c926980cab11f..d375a6e0c09ea 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty13.errors.txt +++ b/tests/baselines/reference/checkJsxChildrenProperty13.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/jsx/file.tsx(12,30): error TS2710: 'children' are specified twice. The attribute named 'children' will be overwritten. +tests/cases/conformance/jsx/file.tsx(12,46): error TS2735: 'children' is overwritten by a later spread. ==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== @@ -14,8 +14,8 @@ tests/cases/conformance/jsx/file.tsx(12,30): error TS2710: 'children' are specif render() { // Error children are specified twice return ( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2710: 'children' are specified twice. The attribute named 'children' will be overwritten. + ~~~~~~~~~~~~~ +!!! error TS2735: 'children' is overwritten by a later spread.
Hello World
); } diff --git a/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt b/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt index ac342678508c5..38f6fae2447a9 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt +++ b/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt @@ -1,6 +1,6 @@ tests/cases/conformance/jsx/file.tsx(14,10): error TS2322: Type '{ a: number; b: string; }' is not assignable to type 'Prop'. Property 'children' is missing in type '{ a: number; b: string; }'. -tests/cases/conformance/jsx/file.tsx(17,11): error TS2710: 'children' are specified twice. The attribute named 'children' will be overwritten. +tests/cases/conformance/jsx/file.tsx(17,25): error TS2735: 'children' is overwritten by a later spread. tests/cases/conformance/jsx/file.tsx(31,6): error TS2322: Type '{ children: (Element | ((name: string) => Element))[]; a: number; b: string; }' is not assignable to type 'Prop'. Types of property 'children' are incompatible. Type '(Element | ((name: string) => Element))[]' is not assignable to type 'string | Element'. @@ -44,8 +44,8 @@ tests/cases/conformance/jsx/file.tsx(49,6): error TS2322: Type '{ children: Elem let k0 = - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2710: 'children' are specified twice. The attribute named 'children' will be overwritten. + ~~~~~~~~~~~~~~~~~ +!!! error TS2735: 'children' is overwritten by a later spread. hi hi hi! ; diff --git a/tests/baselines/reference/excessPropertyCheckWithSpread.errors.txt b/tests/baselines/reference/excessPropertyCheckWithSpread.errors.txt deleted file mode 100644 index 422d7fc280cd5..0000000000000 --- a/tests/baselines/reference/excessPropertyCheckWithSpread.errors.txt +++ /dev/null @@ -1,30 +0,0 @@ -tests/cases/compiler/excessPropertyCheckWithSpread.ts(6,3): error TS2345: Argument of type '{ n: number; a: number; }' is not assignable to parameter of type '{ a: any; }'. - Object literal may only specify known properties, and 'n' does not exist in type '{ a: any; }'. -tests/cases/compiler/excessPropertyCheckWithSpread.ts(16,3): error TS2345: Argument of type '{ opt: string | number; a: number; }' is not assignable to parameter of type '{ a: any; }'. - Object literal may only specify known properties, and 'opt' does not exist in type '{ a: any; }'. - - -==== tests/cases/compiler/excessPropertyCheckWithSpread.ts (2 errors) ==== - declare function f({ a: number }): void - interface I { - readonly n: number; - } - declare let i: I; - f({ a: 1, ...i }); - ~~~~~~~~~~~~~~ -!!! error TS2345: Argument of type '{ n: number; a: number; }' is not assignable to parameter of type '{ a: any; }'. -!!! error TS2345: Object literal may only specify known properties, and 'n' does not exist in type '{ a: any; }'. - - interface R { - opt?: number - } - interface L { - opt: string - } - declare let l: L; - declare let r: R; - f({ a: 1, ...l, ...r }); - ~~~~~~~~~~~~~~~~~~~~ -!!! error TS2345: Argument of type '{ opt: string | number; a: number; }' is not assignable to parameter of type '{ a: any; }'. -!!! error TS2345: Object literal may only specify known properties, and 'opt' does not exist in type '{ a: any; }'. - \ No newline at end of file diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index 1aef3a3bc994d..44cbce202a3a4 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -7,23 +7,14 @@ let addAfter: { a: number, b: string, c: boolean } = { ...o, c: false } let addBefore: { a: number, b: string, c: boolean } = { c: false, ...o } -// Note: ignore still changes the order that properties are printed -let ignore: { a: number, b: string } = - { b: 'ignored', ...o } let override: { a: number, b: string } = { ...o, b: 'override' } let nested: { a: number, b: boolean, c: string } = { ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' } let combined: { a: number, b: string, c: boolean } = { ...o, ...o2 } -let combinedBefore: { a: number, b: string, c: boolean } = - { b: 'ok', ...o, ...o2 } -let combinedMid: { a: number, b: string, c: boolean } = - { ...o, b: 'ok', ...o2 } let combinedAfter: { a: number, b: string, c: boolean } = { ...o, ...o2, b: 'ok' } -let combinedNested: { a: number, b: boolean, c: string, d: string } = - { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } let combinedNestedChangeType: { a: number, b: boolean, c: number } = { ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } let propertyNested: { a: { a: number, b: string } } = @@ -91,8 +82,6 @@ cplus.plus(); // new field's type conflicting with existing field is OK let changeTypeAfter: { a: string, b: string } = { ...o, a: 'wrong type?' } -let changeTypeBefore: { a: number, b: string } = - { a: 'wrong type?', ...o }; let changeTypeBoth: { a: string, b: number } = { ...o, ...swap }; @@ -109,8 +98,6 @@ function container( // computed property let computedFirst: { a: number, b: string, "before everything": number } = { ['before everything']: 12, ...o, b: 'yes' } - let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = - { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } let computedAfter: { a: number, b: string, "at the end": number } = { ...o, b: 'yeah', ['at the end']: 14 } } @@ -138,15 +125,10 @@ var o2 = { b: 'yes', c: true }; var swap = { a: 'yes', b: -1 }; var addAfter = __assign({}, o, { c: false }); var addBefore = __assign({ c: false }, o); -// Note: ignore still changes the order that properties are printed -var ignore = __assign({ b: 'ignored' }, o); var override = __assign({}, o, { b: 'override' }); var nested = __assign({}, __assign({ a: 3 }, { b: false, c: 'overriden' }), { c: 'whatever' }); var combined = __assign({}, o, o2); -var combinedBefore = __assign({ b: 'ok' }, o, o2); -var combinedMid = __assign({}, o, { b: 'ok' }, o2); var combinedAfter = __assign({}, o, o2, { b: 'ok' }); -var combinedNested = __assign({}, __assign({ a: 4 }, { b: false, c: 'overriden' }), { d: 'actually new' }, { a: 5, d: 'maybe new' }); var combinedNestedChangeType = __assign({}, __assign({ a: 1 }, { b: false, c: 'overriden' }), { c: -1 }); var propertyNested = { a: __assign({}, o) }; // accessors don't copy the descriptor @@ -196,18 +178,16 @@ var cplus = __assign({}, c, { plus: function () { return this.p + 1; } }); cplus.plus(); // new field's type conflicting with existing field is OK var changeTypeAfter = __assign({}, o, { a: 'wrong type?' }); -var changeTypeBefore = __assign({ a: 'wrong type?' }, o); var changeTypeBoth = __assign({}, o, swap); // optional function container(definiteBoolean, definiteString, optionalString, optionalNumber) { - var _a, _b, _c; + var _a, _b; var optionalUnionStops = __assign({}, definiteBoolean, definiteString, optionalNumber); var optionalUnionDuplicates = __assign({}, definiteBoolean, definiteString, optionalString, optionalNumber); var allOptional = __assign({}, optionalString, optionalNumber); // computed property var computedFirst = __assign((_a = {}, _a['before everything'] = 12, _a), o, { b: 'yes' }); - var computedMiddle = __assign({}, o, (_b = {}, _b['in the middle'] = 13, _b.b = 'maybe?', _b), o2); - var computedAfter = __assign({}, o, (_c = { b: 'yeah' }, _c['at the end'] = 14, _c)); + var computedAfter = __assign({}, o, (_b = { b: 'yeah' }, _b['at the end'] = 14, _b)); } // shortcut syntax var a = 12; diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index 0bbcd4a9f4b51..f8bc6b5494077 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -34,324 +34,268 @@ let addBefore: { a: number, b: string, c: boolean } = >c : Symbol(c, Decl(objectSpread.ts, 7, 5)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) -// Note: ignore still changes the order that properties are printed -let ignore: { a: number, b: string } = ->ignore : Symbol(ignore, Decl(objectSpread.ts, 9, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 9, 13)) ->b : Symbol(b, Decl(objectSpread.ts, 9, 24)) - - { b: 'ignored', ...o } ->b : Symbol(b, Decl(objectSpread.ts, 10, 5)) ->o : Symbol(o, Decl(objectSpread.ts, 0, 3)) - let override: { a: number, b: string } = ->override : Symbol(override, Decl(objectSpread.ts, 11, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 11, 15)) ->b : Symbol(b, Decl(objectSpread.ts, 11, 26)) +>override : Symbol(override, Decl(objectSpread.ts, 8, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 8, 15)) +>b : Symbol(b, Decl(objectSpread.ts, 8, 26)) { ...o, b: 'override' } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->b : Symbol(b, Decl(objectSpread.ts, 12, 11)) +>b : Symbol(b, Decl(objectSpread.ts, 9, 11)) let nested: { a: number, b: boolean, c: string } = ->nested : Symbol(nested, Decl(objectSpread.ts, 13, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 13, 13)) ->b : Symbol(b, Decl(objectSpread.ts, 13, 24)) ->c : Symbol(c, Decl(objectSpread.ts, 13, 36)) +>nested : Symbol(nested, Decl(objectSpread.ts, 10, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 10, 13)) +>b : Symbol(b, Decl(objectSpread.ts, 10, 24)) +>c : Symbol(c, Decl(objectSpread.ts, 10, 36)) { ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' } ->a : Symbol(a, Decl(objectSpread.ts, 14, 10)) ->b : Symbol(b, Decl(objectSpread.ts, 14, 21)) ->c : Symbol(c, Decl(objectSpread.ts, 14, 31)) ->c : Symbol(c, Decl(objectSpread.ts, 14, 51)) +>a : Symbol(a, Decl(objectSpread.ts, 11, 10)) +>b : Symbol(b, Decl(objectSpread.ts, 11, 21)) +>c : Symbol(c, Decl(objectSpread.ts, 11, 31)) +>c : Symbol(c, Decl(objectSpread.ts, 11, 51)) let combined: { a: number, b: string, c: boolean } = ->combined : Symbol(combined, Decl(objectSpread.ts, 15, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 15, 15)) ->b : Symbol(b, Decl(objectSpread.ts, 15, 26)) ->c : Symbol(c, Decl(objectSpread.ts, 15, 37)) +>combined : Symbol(combined, Decl(objectSpread.ts, 12, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 12, 15)) +>b : Symbol(b, Decl(objectSpread.ts, 12, 26)) +>c : Symbol(c, Decl(objectSpread.ts, 12, 37)) { ...o, ...o2 } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) >o2 : Symbol(o2, Decl(objectSpread.ts, 1, 3)) -let combinedBefore: { a: number, b: string, c: boolean } = ->combinedBefore : Symbol(combinedBefore, Decl(objectSpread.ts, 17, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 17, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 17, 32)) ->c : Symbol(c, Decl(objectSpread.ts, 17, 43)) - - { b: 'ok', ...o, ...o2 } ->b : Symbol(b, Decl(objectSpread.ts, 18, 5)) ->o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->o2 : Symbol(o2, Decl(objectSpread.ts, 1, 3)) - -let combinedMid: { a: number, b: string, c: boolean } = ->combinedMid : Symbol(combinedMid, Decl(objectSpread.ts, 19, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 19, 18)) ->b : Symbol(b, Decl(objectSpread.ts, 19, 29)) ->c : Symbol(c, Decl(objectSpread.ts, 19, 40)) - - { ...o, b: 'ok', ...o2 } ->o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->b : Symbol(b, Decl(objectSpread.ts, 20, 11)) ->o2 : Symbol(o2, Decl(objectSpread.ts, 1, 3)) - let combinedAfter: { a: number, b: string, c: boolean } = ->combinedAfter : Symbol(combinedAfter, Decl(objectSpread.ts, 21, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 21, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 21, 31)) ->c : Symbol(c, Decl(objectSpread.ts, 21, 42)) +>combinedAfter : Symbol(combinedAfter, Decl(objectSpread.ts, 14, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 14, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 14, 31)) +>c : Symbol(c, Decl(objectSpread.ts, 14, 42)) { ...o, ...o2, b: 'ok' } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) >o2 : Symbol(o2, Decl(objectSpread.ts, 1, 3)) ->b : Symbol(b, Decl(objectSpread.ts, 22, 18)) - -let combinedNested: { a: number, b: boolean, c: string, d: string } = ->combinedNested : Symbol(combinedNested, Decl(objectSpread.ts, 23, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 23, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 23, 32)) ->c : Symbol(c, Decl(objectSpread.ts, 23, 44)) ->d : Symbol(d, Decl(objectSpread.ts, 23, 55)) - - { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } ->a : Symbol(a, Decl(objectSpread.ts, 24, 10)) ->b : Symbol(b, Decl(objectSpread.ts, 24, 21)) ->c : Symbol(c, Decl(objectSpread.ts, 24, 31)) ->d : Symbol(d, Decl(objectSpread.ts, 24, 51)) ->a : Symbol(a, Decl(objectSpread.ts, 24, 75)) ->d : Symbol(d, Decl(objectSpread.ts, 24, 81)) +>b : Symbol(b, Decl(objectSpread.ts, 15, 18)) let combinedNestedChangeType: { a: number, b: boolean, c: number } = ->combinedNestedChangeType : Symbol(combinedNestedChangeType, Decl(objectSpread.ts, 25, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 25, 31)) ->b : Symbol(b, Decl(objectSpread.ts, 25, 42)) ->c : Symbol(c, Decl(objectSpread.ts, 25, 54)) +>combinedNestedChangeType : Symbol(combinedNestedChangeType, Decl(objectSpread.ts, 16, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 16, 31)) +>b : Symbol(b, Decl(objectSpread.ts, 16, 42)) +>c : Symbol(c, Decl(objectSpread.ts, 16, 54)) { ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } ->a : Symbol(a, Decl(objectSpread.ts, 26, 10)) ->b : Symbol(b, Decl(objectSpread.ts, 26, 21)) ->c : Symbol(c, Decl(objectSpread.ts, 26, 31)) ->c : Symbol(c, Decl(objectSpread.ts, 26, 51)) +>a : Symbol(a, Decl(objectSpread.ts, 17, 10)) +>b : Symbol(b, Decl(objectSpread.ts, 17, 21)) +>c : Symbol(c, Decl(objectSpread.ts, 17, 31)) +>c : Symbol(c, Decl(objectSpread.ts, 17, 51)) let propertyNested: { a: { a: number, b: string } } = ->propertyNested : Symbol(propertyNested, Decl(objectSpread.ts, 27, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 27, 21)) ->a : Symbol(a, Decl(objectSpread.ts, 27, 26)) ->b : Symbol(b, Decl(objectSpread.ts, 27, 37)) +>propertyNested : Symbol(propertyNested, Decl(objectSpread.ts, 18, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 18, 21)) +>a : Symbol(a, Decl(objectSpread.ts, 18, 26)) +>b : Symbol(b, Decl(objectSpread.ts, 18, 37)) { a: { ... o } } ->a : Symbol(a, Decl(objectSpread.ts, 28, 5)) +>a : Symbol(a, Decl(objectSpread.ts, 19, 5)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) // accessors don't copy the descriptor // (which means that readonly getters become read/write properties) let op = { get a () { return 6 } }; ->op : Symbol(op, Decl(objectSpread.ts, 31, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 31, 10)) +>op : Symbol(op, Decl(objectSpread.ts, 22, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 22, 10)) let getter: { a: number, c: number } = ->getter : Symbol(getter, Decl(objectSpread.ts, 32, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 32, 13)) ->c : Symbol(c, Decl(objectSpread.ts, 32, 24)) +>getter : Symbol(getter, Decl(objectSpread.ts, 23, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 23, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 23, 24)) { ...op, c: 7 } ->op : Symbol(op, Decl(objectSpread.ts, 31, 3)) ->c : Symbol(c, Decl(objectSpread.ts, 33, 12)) +>op : Symbol(op, Decl(objectSpread.ts, 22, 3)) +>c : Symbol(c, Decl(objectSpread.ts, 24, 12)) getter.a = 12; ->getter.a : Symbol(a, Decl(objectSpread.ts, 32, 13)) ->getter : Symbol(getter, Decl(objectSpread.ts, 32, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 32, 13)) +>getter.a : Symbol(a, Decl(objectSpread.ts, 23, 13)) +>getter : Symbol(getter, Decl(objectSpread.ts, 23, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 23, 13)) // functions result in { } let spreadFunc = { ...(function () { }) }; ->spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 37, 3)) +>spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 28, 3)) type Header = { head: string, body: string, authToken: string } ->Header : Symbol(Header, Decl(objectSpread.ts, 37, 42)) ->head : Symbol(head, Decl(objectSpread.ts, 39, 15)) ->body : Symbol(body, Decl(objectSpread.ts, 39, 29)) ->authToken : Symbol(authToken, Decl(objectSpread.ts, 39, 43)) +>Header : Symbol(Header, Decl(objectSpread.ts, 28, 42)) +>head : Symbol(head, Decl(objectSpread.ts, 30, 15)) +>body : Symbol(body, Decl(objectSpread.ts, 30, 29)) +>authToken : Symbol(authToken, Decl(objectSpread.ts, 30, 43)) function from16326(this: { header: Header }, header: Header, authToken: string): Header { ->from16326 : Symbol(from16326, Decl(objectSpread.ts, 39, 63)) ->this : Symbol(this, Decl(objectSpread.ts, 40, 19)) ->header : Symbol(header, Decl(objectSpread.ts, 40, 26)) ->Header : Symbol(Header, Decl(objectSpread.ts, 37, 42)) ->header : Symbol(header, Decl(objectSpread.ts, 40, 44)) ->Header : Symbol(Header, Decl(objectSpread.ts, 37, 42)) ->authToken : Symbol(authToken, Decl(objectSpread.ts, 40, 60)) ->Header : Symbol(Header, Decl(objectSpread.ts, 37, 42)) +>from16326 : Symbol(from16326, Decl(objectSpread.ts, 30, 63)) +>this : Symbol(this, Decl(objectSpread.ts, 31, 19)) +>header : Symbol(header, Decl(objectSpread.ts, 31, 26)) +>Header : Symbol(Header, Decl(objectSpread.ts, 28, 42)) +>header : Symbol(header, Decl(objectSpread.ts, 31, 44)) +>Header : Symbol(Header, Decl(objectSpread.ts, 28, 42)) +>authToken : Symbol(authToken, Decl(objectSpread.ts, 31, 60)) +>Header : Symbol(Header, Decl(objectSpread.ts, 28, 42)) return { ...this.header, ->this.header : Symbol(header, Decl(objectSpread.ts, 40, 26)) ->this : Symbol(this, Decl(objectSpread.ts, 40, 19)) ->header : Symbol(header, Decl(objectSpread.ts, 40, 26)) +>this.header : Symbol(header, Decl(objectSpread.ts, 31, 26)) +>this : Symbol(this, Decl(objectSpread.ts, 31, 19)) +>header : Symbol(header, Decl(objectSpread.ts, 31, 26)) ...header, ->header : Symbol(header, Decl(objectSpread.ts, 40, 44)) +>header : Symbol(header, Decl(objectSpread.ts, 31, 44)) ...authToken && { authToken } ->authToken : Symbol(authToken, Decl(objectSpread.ts, 40, 60)) ->authToken : Symbol(authToken, Decl(objectSpread.ts, 44, 25)) +>authToken : Symbol(authToken, Decl(objectSpread.ts, 31, 60)) +>authToken : Symbol(authToken, Decl(objectSpread.ts, 35, 25)) } } // boolean && T results in Partial function conditionalSpreadBoolean(b: boolean) : { x: number, y: number } { ->conditionalSpreadBoolean : Symbol(conditionalSpreadBoolean, Decl(objectSpread.ts, 46, 1)) ->b : Symbol(b, Decl(objectSpread.ts, 48, 34)) ->x : Symbol(x, Decl(objectSpread.ts, 48, 49)) ->y : Symbol(y, Decl(objectSpread.ts, 48, 60)) +>conditionalSpreadBoolean : Symbol(conditionalSpreadBoolean, Decl(objectSpread.ts, 37, 1)) +>b : Symbol(b, Decl(objectSpread.ts, 39, 34)) +>x : Symbol(x, Decl(objectSpread.ts, 39, 49)) +>y : Symbol(y, Decl(objectSpread.ts, 39, 60)) let o = { x: 12, y: 13 } ->o : Symbol(o, Decl(objectSpread.ts, 49, 7)) ->x : Symbol(x, Decl(objectSpread.ts, 49, 13)) ->y : Symbol(y, Decl(objectSpread.ts, 49, 20)) +>o : Symbol(o, Decl(objectSpread.ts, 40, 7)) +>x : Symbol(x, Decl(objectSpread.ts, 40, 13)) +>y : Symbol(y, Decl(objectSpread.ts, 40, 20)) o = { ->o : Symbol(o, Decl(objectSpread.ts, 49, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 40, 7)) ...o, ->o : Symbol(o, Decl(objectSpread.ts, 49, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 40, 7)) ...b && { x: 14 } ->b : Symbol(b, Decl(objectSpread.ts, 48, 34)) ->x : Symbol(x, Decl(objectSpread.ts, 52, 17)) +>b : Symbol(b, Decl(objectSpread.ts, 39, 34)) +>x : Symbol(x, Decl(objectSpread.ts, 43, 17)) } let o2 = { ...b && { x: 21 }} ->o2 : Symbol(o2, Decl(objectSpread.ts, 54, 7)) ->b : Symbol(b, Decl(objectSpread.ts, 48, 34)) ->x : Symbol(x, Decl(objectSpread.ts, 54, 24)) +>o2 : Symbol(o2, Decl(objectSpread.ts, 45, 7)) +>b : Symbol(b, Decl(objectSpread.ts, 39, 34)) +>x : Symbol(x, Decl(objectSpread.ts, 45, 24)) return o; ->o : Symbol(o, Decl(objectSpread.ts, 49, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 40, 7)) } function conditionalSpreadNumber(nt: number): { x: number, y: number } { ->conditionalSpreadNumber : Symbol(conditionalSpreadNumber, Decl(objectSpread.ts, 56, 1)) ->nt : Symbol(nt, Decl(objectSpread.ts, 57, 33)) ->x : Symbol(x, Decl(objectSpread.ts, 57, 47)) ->y : Symbol(y, Decl(objectSpread.ts, 57, 58)) +>conditionalSpreadNumber : Symbol(conditionalSpreadNumber, Decl(objectSpread.ts, 47, 1)) +>nt : Symbol(nt, Decl(objectSpread.ts, 48, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 48, 47)) +>y : Symbol(y, Decl(objectSpread.ts, 48, 58)) let o = { x: 15, y: 16 } ->o : Symbol(o, Decl(objectSpread.ts, 58, 7)) ->x : Symbol(x, Decl(objectSpread.ts, 58, 13)) ->y : Symbol(y, Decl(objectSpread.ts, 58, 20)) +>o : Symbol(o, Decl(objectSpread.ts, 49, 7)) +>x : Symbol(x, Decl(objectSpread.ts, 49, 13)) +>y : Symbol(y, Decl(objectSpread.ts, 49, 20)) o = { ->o : Symbol(o, Decl(objectSpread.ts, 58, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 49, 7)) ...o, ->o : Symbol(o, Decl(objectSpread.ts, 58, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 49, 7)) ...nt && { x: nt } ->nt : Symbol(nt, Decl(objectSpread.ts, 57, 33)) ->x : Symbol(x, Decl(objectSpread.ts, 61, 18)) ->nt : Symbol(nt, Decl(objectSpread.ts, 57, 33)) +>nt : Symbol(nt, Decl(objectSpread.ts, 48, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 52, 18)) +>nt : Symbol(nt, Decl(objectSpread.ts, 48, 33)) } let o2 = { ...nt && { x: nt }} ->o2 : Symbol(o2, Decl(objectSpread.ts, 63, 7)) ->nt : Symbol(nt, Decl(objectSpread.ts, 57, 33)) ->x : Symbol(x, Decl(objectSpread.ts, 63, 25)) ->nt : Symbol(nt, Decl(objectSpread.ts, 57, 33)) +>o2 : Symbol(o2, Decl(objectSpread.ts, 54, 7)) +>nt : Symbol(nt, Decl(objectSpread.ts, 48, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 54, 25)) +>nt : Symbol(nt, Decl(objectSpread.ts, 48, 33)) return o; ->o : Symbol(o, Decl(objectSpread.ts, 58, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 49, 7)) } function conditionalSpreadString(st: string): { x: string, y: number } { ->conditionalSpreadString : Symbol(conditionalSpreadString, Decl(objectSpread.ts, 65, 1)) ->st : Symbol(st, Decl(objectSpread.ts, 66, 33)) ->x : Symbol(x, Decl(objectSpread.ts, 66, 47)) ->y : Symbol(y, Decl(objectSpread.ts, 66, 58)) +>conditionalSpreadString : Symbol(conditionalSpreadString, Decl(objectSpread.ts, 56, 1)) +>st : Symbol(st, Decl(objectSpread.ts, 57, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 57, 47)) +>y : Symbol(y, Decl(objectSpread.ts, 57, 58)) let o = { x: 'hi', y: 17 } ->o : Symbol(o, Decl(objectSpread.ts, 67, 7)) ->x : Symbol(x, Decl(objectSpread.ts, 67, 13)) ->y : Symbol(y, Decl(objectSpread.ts, 67, 22)) +>o : Symbol(o, Decl(objectSpread.ts, 58, 7)) +>x : Symbol(x, Decl(objectSpread.ts, 58, 13)) +>y : Symbol(y, Decl(objectSpread.ts, 58, 22)) o = { ->o : Symbol(o, Decl(objectSpread.ts, 67, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 58, 7)) ...o, ->o : Symbol(o, Decl(objectSpread.ts, 67, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 58, 7)) ...st && { x: st } ->st : Symbol(st, Decl(objectSpread.ts, 66, 33)) ->x : Symbol(x, Decl(objectSpread.ts, 70, 18)) ->st : Symbol(st, Decl(objectSpread.ts, 66, 33)) +>st : Symbol(st, Decl(objectSpread.ts, 57, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 61, 18)) +>st : Symbol(st, Decl(objectSpread.ts, 57, 33)) } let o2 = { ...st && { x: st }} ->o2 : Symbol(o2, Decl(objectSpread.ts, 72, 7)) ->st : Symbol(st, Decl(objectSpread.ts, 66, 33)) ->x : Symbol(x, Decl(objectSpread.ts, 72, 25)) ->st : Symbol(st, Decl(objectSpread.ts, 66, 33)) +>o2 : Symbol(o2, Decl(objectSpread.ts, 63, 7)) +>st : Symbol(st, Decl(objectSpread.ts, 57, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 63, 25)) +>st : Symbol(st, Decl(objectSpread.ts, 57, 33)) return o; ->o : Symbol(o, Decl(objectSpread.ts, 67, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 58, 7)) } // any results in any let anything: any; ->anything : Symbol(anything, Decl(objectSpread.ts, 77, 3)) +>anything : Symbol(anything, Decl(objectSpread.ts, 68, 3)) let spreadAny = { ...anything }; ->spreadAny : Symbol(spreadAny, Decl(objectSpread.ts, 78, 3)) ->anything : Symbol(anything, Decl(objectSpread.ts, 77, 3)) +>spreadAny : Symbol(spreadAny, Decl(objectSpread.ts, 69, 3)) +>anything : Symbol(anything, Decl(objectSpread.ts, 68, 3)) // methods are not enumerable class C { p = 1; m() { } } ->C : Symbol(C, Decl(objectSpread.ts, 78, 32)) ->p : Symbol(C.p, Decl(objectSpread.ts, 81, 9)) ->m : Symbol(C.m, Decl(objectSpread.ts, 81, 16)) +>C : Symbol(C, Decl(objectSpread.ts, 69, 32)) +>p : Symbol(C.p, Decl(objectSpread.ts, 72, 9)) +>m : Symbol(C.m, Decl(objectSpread.ts, 72, 16)) let c: C = new C() ->c : Symbol(c, Decl(objectSpread.ts, 82, 3)) ->C : Symbol(C, Decl(objectSpread.ts, 78, 32)) ->C : Symbol(C, Decl(objectSpread.ts, 78, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 73, 3)) +>C : Symbol(C, Decl(objectSpread.ts, 69, 32)) +>C : Symbol(C, Decl(objectSpread.ts, 69, 32)) let spreadC: { p: number } = { ...c } ->spreadC : Symbol(spreadC, Decl(objectSpread.ts, 83, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 83, 14)) ->c : Symbol(c, Decl(objectSpread.ts, 82, 3)) +>spreadC : Symbol(spreadC, Decl(objectSpread.ts, 74, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 74, 14)) +>c : Symbol(c, Decl(objectSpread.ts, 73, 3)) // own methods are enumerable let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; ->cplus : Symbol(cplus, Decl(objectSpread.ts, 86, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 86, 12)) ->plus : Symbol(plus, Decl(objectSpread.ts, 86, 23)) ->c : Symbol(c, Decl(objectSpread.ts, 82, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 86, 48)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 77, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 77, 12)) +>plus : Symbol(plus, Decl(objectSpread.ts, 77, 23)) +>c : Symbol(c, Decl(objectSpread.ts, 73, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 77, 48)) cplus.plus(); ->cplus.plus : Symbol(plus, Decl(objectSpread.ts, 86, 23)) ->cplus : Symbol(cplus, Decl(objectSpread.ts, 86, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 86, 23)) +>cplus.plus : Symbol(plus, Decl(objectSpread.ts, 77, 23)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 77, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 77, 23)) // new field's type conflicting with existing field is OK let changeTypeAfter: { a: string, b: string } = ->changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 90, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 90, 22)) ->b : Symbol(b, Decl(objectSpread.ts, 90, 33)) +>changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 81, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 81, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 81, 33)) { ...o, a: 'wrong type?' } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 91, 11)) - -let changeTypeBefore: { a: number, b: string } = ->changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 92, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 92, 23)) ->b : Symbol(b, Decl(objectSpread.ts, 92, 34)) - - { a: 'wrong type?', ...o }; ->a : Symbol(a, Decl(objectSpread.ts, 93, 5)) ->o : Symbol(o, Decl(objectSpread.ts, 0, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 82, 11)) let changeTypeBoth: { a: string, b: number } = ->changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 94, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 94, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 94, 32)) +>changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 83, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 83, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 83, 32)) { ...o, ...swap }; >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) @@ -359,96 +303,82 @@ let changeTypeBoth: { a: string, b: number } = // optional function container( ->container : Symbol(container, Decl(objectSpread.ts, 95, 22)) +>container : Symbol(container, Decl(objectSpread.ts, 84, 22)) definiteBoolean: { sn: boolean }, ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 98, 19)) ->sn : Symbol(sn, Decl(objectSpread.ts, 99, 22)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 87, 19)) +>sn : Symbol(sn, Decl(objectSpread.ts, 88, 22)) definiteString: { sn: string }, ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 99, 37)) ->sn : Symbol(sn, Decl(objectSpread.ts, 100, 21)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 88, 37)) +>sn : Symbol(sn, Decl(objectSpread.ts, 89, 21)) optionalString: { sn?: string }, ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 100, 35)) ->sn : Symbol(sn, Decl(objectSpread.ts, 101, 21)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 89, 35)) +>sn : Symbol(sn, Decl(objectSpread.ts, 90, 21)) optionalNumber: { sn?: number }) { ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 101, 36)) ->sn : Symbol(sn, Decl(objectSpread.ts, 102, 21)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 90, 36)) +>sn : Symbol(sn, Decl(objectSpread.ts, 91, 21)) let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; ->optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 103, 7)) ->sn : Symbol(sn, Decl(objectSpread.ts, 103, 29)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 98, 19)) ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 99, 37)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 101, 36)) +>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 92, 7)) +>sn : Symbol(sn, Decl(objectSpread.ts, 92, 29)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 87, 19)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 88, 37)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 90, 36)) let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; ->optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 104, 7)) ->sn : Symbol(sn, Decl(objectSpread.ts, 104, 34)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 98, 19)) ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 99, 37)) ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 100, 35)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 101, 36)) +>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 93, 7)) +>sn : Symbol(sn, Decl(objectSpread.ts, 93, 34)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 87, 19)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 88, 37)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 89, 35)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 90, 36)) let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; ->allOptional : Symbol(allOptional, Decl(objectSpread.ts, 105, 7)) ->sn : Symbol(sn, Decl(objectSpread.ts, 105, 22)) ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 100, 35)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 101, 36)) +>allOptional : Symbol(allOptional, Decl(objectSpread.ts, 94, 7)) +>sn : Symbol(sn, Decl(objectSpread.ts, 94, 22)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 89, 35)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 90, 36)) // computed property let computedFirst: { a: number, b: string, "before everything": number } = ->computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 108, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 108, 24)) ->b : Symbol(b, Decl(objectSpread.ts, 108, 35)) ->"before everything" : Symbol("before everything", Decl(objectSpread.ts, 108, 46)) +>computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 97, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 97, 24)) +>b : Symbol(b, Decl(objectSpread.ts, 97, 35)) +>"before everything" : Symbol("before everything", Decl(objectSpread.ts, 97, 46)) { ['before everything']: 12, ...o, b: 'yes' } ->['before everything'] : Symbol(['before everything'], Decl(objectSpread.ts, 109, 9)) ->'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 109, 9)) ->o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->b : Symbol(b, Decl(objectSpread.ts, 109, 42)) - - let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = ->computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 110, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 110, 25)) ->b : Symbol(b, Decl(objectSpread.ts, 110, 36)) ->c : Symbol(c, Decl(objectSpread.ts, 110, 47)) ->"in the middle" : Symbol("in the middle", Decl(objectSpread.ts, 110, 59)) - - { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } +>['before everything'] : Symbol(['before everything'], Decl(objectSpread.ts, 98, 9)) +>'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 98, 9)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->['in the middle'] : Symbol(['in the middle'], Decl(objectSpread.ts, 111, 15)) ->'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 111, 15)) ->b : Symbol(b, Decl(objectSpread.ts, 111, 38)) ->o2 : Symbol(o2, Decl(objectSpread.ts, 1, 3)) +>b : Symbol(b, Decl(objectSpread.ts, 98, 42)) let computedAfter: { a: number, b: string, "at the end": number } = ->computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 112, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 112, 24)) ->b : Symbol(b, Decl(objectSpread.ts, 112, 35)) ->"at the end" : Symbol("at the end", Decl(objectSpread.ts, 112, 46)) +>computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 99, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 99, 24)) +>b : Symbol(b, Decl(objectSpread.ts, 99, 35)) +>"at the end" : Symbol("at the end", Decl(objectSpread.ts, 99, 46)) { ...o, b: 'yeah', ['at the end']: 14 } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->b : Symbol(b, Decl(objectSpread.ts, 113, 15)) ->['at the end'] : Symbol(['at the end'], Decl(objectSpread.ts, 113, 26)) ->'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 113, 26)) +>b : Symbol(b, Decl(objectSpread.ts, 100, 15)) +>['at the end'] : Symbol(['at the end'], Decl(objectSpread.ts, 100, 26)) +>'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 100, 26)) } // shortcut syntax let a = 12; ->a : Symbol(a, Decl(objectSpread.ts, 116, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 103, 3)) let shortCutted: { a: number, b: string } = { ...o, a } ->shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 117, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 117, 18)) ->b : Symbol(b, Decl(objectSpread.ts, 117, 29)) +>shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 104, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 104, 18)) +>b : Symbol(b, Decl(objectSpread.ts, 104, 29)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 117, 51)) +>a : Symbol(a, Decl(objectSpread.ts, 104, 51)) // non primitive let spreadNonPrimitive = { ...{}}; ->spreadNonPrimitive : Symbol(spreadNonPrimitive, Decl(objectSpread.ts, 119, 3)) +>spreadNonPrimitive : Symbol(spreadNonPrimitive, Decl(objectSpread.ts, 106, 3)) diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index fc60b0d88cf44..b93e0282acdac 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -48,18 +48,6 @@ let addBefore: { a: number, b: string, c: boolean } = >false : false >o : { a: number; b: string; } -// Note: ignore still changes the order that properties are printed -let ignore: { a: number, b: string } = ->ignore : { a: number; b: string; } ->a : number ->b : string - - { b: 'ignored', ...o } ->{ b: 'ignored', ...o } : { a: number; b: string; } ->b : string ->'ignored' : "ignored" ->o : { a: number; b: string; } - let override: { a: number, b: string } = >override : { a: number; b: string; } >a : number @@ -101,32 +89,6 @@ let combined: { a: number, b: string, c: boolean } = >o : { a: number; b: string; } >o2 : { b: string; c: boolean; } -let combinedBefore: { a: number, b: string, c: boolean } = ->combinedBefore : { a: number; b: string; c: boolean; } ->a : number ->b : string ->c : boolean - - { b: 'ok', ...o, ...o2 } ->{ b: 'ok', ...o, ...o2 } : { b: string; c: boolean; a: number; } ->b : string ->'ok' : "ok" ->o : { a: number; b: string; } ->o2 : { b: string; c: boolean; } - -let combinedMid: { a: number, b: string, c: boolean } = ->combinedMid : { a: number; b: string; c: boolean; } ->a : number ->b : string ->c : boolean - - { ...o, b: 'ok', ...o2 } ->{ ...o, b: 'ok', ...o2 } : { b: string; c: boolean; a: number; } ->o : { a: number; b: string; } ->b : string ->'ok' : "ok" ->o2 : { b: string; c: boolean; } - let combinedAfter: { a: number, b: string, c: boolean } = >combinedAfter : { a: number; b: string; c: boolean; } >a : number @@ -140,31 +102,6 @@ let combinedAfter: { a: number, b: string, c: boolean } = >b : string >'ok' : "ok" -let combinedNested: { a: number, b: boolean, c: string, d: string } = ->combinedNested : { a: number; b: boolean; c: string; d: string; } ->a : number ->b : boolean ->c : string ->d : string - - { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } ->{ ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } : { a: number; d: string; b: false; c: string; } ->{ a: 4, ...{ b: false, c: 'overriden' } } : { b: false; c: string; a: number; } ->a : number ->4 : 4 ->{ b: false, c: 'overriden' } : { b: false; c: string; } ->b : false ->false : false ->c : string ->'overriden' : "overriden" ->d : string ->'actually new' : "actually new" ->{ a: 5, d: 'maybe new' } : { a: number; d: string; } ->a : number ->5 : 5 ->d : string ->'maybe new' : "maybe new" - let combinedNestedChangeType: { a: number, b: boolean, c: number } = >combinedNestedChangeType : { a: number; b: boolean; c: number; } >a : number @@ -445,17 +382,6 @@ let changeTypeAfter: { a: string, b: string } = >a : string >'wrong type?' : "wrong type?" -let changeTypeBefore: { a: number, b: string } = ->changeTypeBefore : { a: number; b: string; } ->a : number ->b : string - - { a: 'wrong type?', ...o }; ->{ a: 'wrong type?', ...o } : { a: number; b: string; } ->a : string ->'wrong type?' : "wrong type?" ->o : { a: number; b: string; } - let changeTypeBoth: { a: string, b: number } = >changeTypeBoth : { a: string; b: number; } >a : string @@ -526,23 +452,6 @@ function container( >b : string >'yes' : "yes" - let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = ->computedMiddle : { a: number; b: string; c: boolean; "in the middle": number; } ->a : number ->b : string ->c : boolean ->"in the middle" : number - - { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } ->{ ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } : { b: string; c: boolean; ['in the middle']: number; a: number; } ->o : { a: number; b: string; } ->['in the middle'] : number ->'in the middle' : "in the middle" ->13 : 13 ->b : string ->'maybe?' : "maybe?" ->o2 : { b: string; c: boolean; } - let computedAfter: { a: number, b: string, "at the end": number } = >computedAfter : { a: number; b: string; "at the end": number; } >a : number diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 1af059068733e..57de2e1797d2b 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -5,22 +5,29 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(23,1): error TS2322 Property 'b' is missing in type '{ s: string; }'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,1): error TS2322: Type '{ b: boolean; }' is not assignable to type '{ s: string; b: boolean; }'. Property 's' is missing in type '{ b: boolean; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,36): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,53): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,20): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(36,20): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(38,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(43,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(47,12): error TS2339: Property 'b' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(53,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,11): error TS2339: Property 'a' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(62,14): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(65,14): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(27,20): error TS2735: 'b' is overwritten by a later spread. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(27,36): error TS2300: Duplicate identifier 'b'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(27,53): error TS2300: Duplicate identifier 'b'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(31,7): error TS2735: 'b' is overwritten by a later spread. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(36,7): error TS2735: 'b' is overwritten by a later spread. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(38,14): error TS2735: 'b' is overwritten by a later spread. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(40,53): error TS2735: 'd' is overwritten by a later spread. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(42,7): error TS2735: 'a' is overwritten by a later spread. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(44,37): error TS2735: 'b' is overwritten by a later spread. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(47,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(48,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(49,20): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(51,20): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(53,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(62,12): error TS2339: Property 'b' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(68,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(73,11): error TS2339: Property 'a' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(77,14): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(80,14): error TS2698: Spread types may only be created from object types. -==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (17 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (24 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -58,13 +65,42 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(65,14): error TS269 !!! error TS2322: Type '{ b: boolean; }' is not assignable to type '{ s: string; b: boolean; }'. !!! error TS2322: Property 's' is missing in type '{ b: boolean; }'. - // literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } + ~~~~~~~~ +!!! error TS2735: 'b' is overwritten by a later spread. ~ !!! error TS2300: Duplicate identifier 'b'. ~ !!! error TS2300: Duplicate identifier 'b'. let duplicatedSpread = { ...o, ...o } + // Note: ignore changes the order that properties are printed + let ignore: { a: number, b: string } = + { b: 'ignored', ...o } + ~~~~~~~~~~~~ +!!! error TS2735: 'b' is overwritten by a later spread. + + let o3 = { a: 1, b: 'no' } + let o4 = { b: 'yes', c: true } + let combinedBefore: { a: number, b: string, c: boolean } = + { b: 'ok', ...o3, ...o4 } + ~~~~~~~ +!!! error TS2735: 'b' is overwritten by a later spread. + let combinedMid: { a: number, b: string, c: boolean } = + { ...o3, b: 'ok', ...o4 } + ~~~~~~~ +!!! error TS2735: 'b' is overwritten by a later spread. + 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 TS2735: 'd' is overwritten by a later spread. + let changeTypeBefore: { a: number, b: string } = + { a: 'wrong type?', ...o3 }; + ~~~~~~~~~~~~~~~~ +!!! error TS2735: 'a' is overwritten by a later spread. + let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = + { ...o3, ['in the middle']: 13, b: 'maybe?', ...o4 } + ~~~~~~~~~~~ +!!! error TS2735: 'b' is overwritten by a later spread. // primitives are not allowed, except for falsy ones let spreadNum = { ...12 }; diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index 35d8cdf9830fc..228ed17a34d35 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -25,9 +25,24 @@ spread = { s: "foo" }; // error, missing 'b' let b = { b: false }; spread = b; // error, missing 's' -// literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } +// Note: ignore changes the order that properties are printed +let ignore: { a: number, b: string } = + { b: 'ignored', ...o } + +let o3 = { a: 1, b: 'no' } +let o4 = { b: 'yes', c: true } +let combinedBefore: { a: number, b: string, c: boolean } = + { b: 'ok', ...o3, ...o4 } +let combinedMid: { a: number, b: string, c: boolean } = + { ...o3, b: 'ok', ...o4 } +let combinedNested: { a: number, b: boolean, c: string, d: string } = + { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } +let changeTypeBefore: { a: number, b: string } = + { a: 'wrong type?', ...o3 }; +let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = + { ...o3, ['in the middle']: 13, b: 'maybe?', ...o4 } // primitives are not allowed, except for falsy ones let spreadNum = { ...12 }; @@ -87,6 +102,7 @@ var __assign = (this && this.__assign) || function () { }; return __assign.apply(this, arguments); }; +var _a; var o = { a: 1, b: 'no' }; /// private propagates var PrivateOptionalX = /** @class */ (function () { @@ -112,9 +128,17 @@ var spread = __assign({ b: true }, { s: "foo" }); spread = { s: "foo" }; // error, missing 'b' var b = { b: false }; spread = b; // error, missing 's' -// literal repeats are not allowed, but spread repeats are fine var duplicated = __assign({ b: 'bad' }, o, { b: 'bad' }, o2, { b: 'bad' }); var duplicatedSpread = __assign({}, o, o); +// Note: ignore changes the order that properties are printed +var ignore = __assign({ b: 'ignored' }, o); +var o3 = { a: 1, b: 'no' }; +var o4 = { b: 'yes', c: true }; +var combinedBefore = __assign({ b: 'ok' }, o3, o4); +var combinedMid = __assign({}, o3, { b: 'ok' }, o4); +var combinedNested = __assign({}, __assign({ a: 4 }, { b: false, c: 'overriden' }), { d: 'actually new' }, { a: 5, d: 'maybe new' }); +var changeTypeBefore = __assign({ a: 'wrong type?' }, o3); +var computedMiddle = __assign({}, o3, (_a = {}, _a['in the middle'] = 13, _a.b = 'maybe?', _a), o4); // primitives are not allowed, except for falsy ones var spreadNum = __assign({}, 12); var spreadSum = __assign({}, 1 + 1); diff --git a/tests/baselines/reference/objectSpreadNegative.symbols b/tests/baselines/reference/objectSpreadNegative.symbols index 4bff16d9be602..1e6f6e31d2aa0 100644 --- a/tests/baselines/reference/objectSpreadNegative.symbols +++ b/tests/baselines/reference/objectSpreadNegative.symbols @@ -76,170 +76,249 @@ spread = b; // error, missing 's' >spread : Symbol(spread, Decl(objectSpreadNegative.ts, 21, 3)) >b : Symbol(b, Decl(objectSpreadNegative.ts, 23, 3)) -// literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } ->duplicated : Symbol(duplicated, Decl(objectSpreadNegative.ts, 27, 3)) ->b : Symbol(b, Decl(objectSpreadNegative.ts, 27, 18), Decl(objectSpreadNegative.ts, 27, 34), Decl(objectSpreadNegative.ts, 27, 51)) +>duplicated : Symbol(duplicated, Decl(objectSpreadNegative.ts, 26, 3)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 26, 18), Decl(objectSpreadNegative.ts, 26, 34), Decl(objectSpreadNegative.ts, 26, 51)) >o : Symbol(o, Decl(objectSpreadNegative.ts, 0, 3)) ->b : Symbol(b, Decl(objectSpreadNegative.ts, 27, 18), Decl(objectSpreadNegative.ts, 27, 34), Decl(objectSpreadNegative.ts, 27, 51)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 26, 18), Decl(objectSpreadNegative.ts, 26, 34), Decl(objectSpreadNegative.ts, 26, 51)) >o2 : Symbol(o2, Decl(objectSpreadNegative.ts, 11, 3)) ->b : Symbol(b, Decl(objectSpreadNegative.ts, 27, 18), Decl(objectSpreadNegative.ts, 27, 34), Decl(objectSpreadNegative.ts, 27, 51)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 26, 18), Decl(objectSpreadNegative.ts, 26, 34), Decl(objectSpreadNegative.ts, 26, 51)) let duplicatedSpread = { ...o, ...o } ->duplicatedSpread : Symbol(duplicatedSpread, Decl(objectSpreadNegative.ts, 28, 3)) +>duplicatedSpread : Symbol(duplicatedSpread, Decl(objectSpreadNegative.ts, 27, 3)) >o : Symbol(o, Decl(objectSpreadNegative.ts, 0, 3)) >o : Symbol(o, Decl(objectSpreadNegative.ts, 0, 3)) +// Note: ignore changes the order that properties are printed +let ignore: { a: number, b: string } = +>ignore : Symbol(ignore, Decl(objectSpreadNegative.ts, 29, 3)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 29, 13)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 29, 24)) + + { b: 'ignored', ...o } +>b : Symbol(b, Decl(objectSpreadNegative.ts, 30, 5)) +>o : Symbol(o, Decl(objectSpreadNegative.ts, 0, 3)) + +let o3 = { a: 1, b: 'no' } +>o3 : Symbol(o3, Decl(objectSpreadNegative.ts, 32, 3)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 32, 10)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 32, 16)) + +let o4 = { b: 'yes', c: true } +>o4 : Symbol(o4, Decl(objectSpreadNegative.ts, 33, 3)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 33, 10)) +>c : Symbol(c, Decl(objectSpreadNegative.ts, 33, 20)) + +let combinedBefore: { a: number, b: string, c: boolean } = +>combinedBefore : Symbol(combinedBefore, Decl(objectSpreadNegative.ts, 34, 3)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 34, 21)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 34, 32)) +>c : Symbol(c, Decl(objectSpreadNegative.ts, 34, 43)) + + { b: 'ok', ...o3, ...o4 } +>b : Symbol(b, Decl(objectSpreadNegative.ts, 35, 5)) +>o3 : Symbol(o3, Decl(objectSpreadNegative.ts, 32, 3)) +>o4 : Symbol(o4, Decl(objectSpreadNegative.ts, 33, 3)) + +let combinedMid: { a: number, b: string, c: boolean } = +>combinedMid : Symbol(combinedMid, Decl(objectSpreadNegative.ts, 36, 3)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 36, 18)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 36, 29)) +>c : Symbol(c, Decl(objectSpreadNegative.ts, 36, 40)) + + { ...o3, b: 'ok', ...o4 } +>o3 : Symbol(o3, Decl(objectSpreadNegative.ts, 32, 3)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 37, 12)) +>o4 : Symbol(o4, Decl(objectSpreadNegative.ts, 33, 3)) + +let combinedNested: { a: number, b: boolean, c: string, d: string } = +>combinedNested : Symbol(combinedNested, Decl(objectSpreadNegative.ts, 38, 3)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 38, 21)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 38, 32)) +>c : Symbol(c, Decl(objectSpreadNegative.ts, 38, 44)) +>d : Symbol(d, Decl(objectSpreadNegative.ts, 38, 55)) + + { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } +>a : Symbol(a, Decl(objectSpreadNegative.ts, 39, 10)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 39, 21)) +>c : Symbol(c, Decl(objectSpreadNegative.ts, 39, 31)) +>d : Symbol(d, Decl(objectSpreadNegative.ts, 39, 51)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 39, 75)) +>d : Symbol(d, Decl(objectSpreadNegative.ts, 39, 81)) + +let changeTypeBefore: { a: number, b: string } = +>changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpreadNegative.ts, 40, 3)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 40, 23)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 40, 34)) + + { a: 'wrong type?', ...o3 }; +>a : Symbol(a, Decl(objectSpreadNegative.ts, 41, 5)) +>o3 : Symbol(o3, Decl(objectSpreadNegative.ts, 32, 3)) + +let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = +>computedMiddle : Symbol(computedMiddle, Decl(objectSpreadNegative.ts, 42, 3)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 42, 21)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 42, 32)) +>c : Symbol(c, Decl(objectSpreadNegative.ts, 42, 43)) +>"in the middle" : Symbol("in the middle", Decl(objectSpreadNegative.ts, 42, 55)) + + { ...o3, ['in the middle']: 13, b: 'maybe?', ...o4 } +>o3 : Symbol(o3, Decl(objectSpreadNegative.ts, 32, 3)) +>['in the middle'] : Symbol(['in the middle'], Decl(objectSpreadNegative.ts, 43, 12)) +>'in the middle' : Symbol(['in the middle'], Decl(objectSpreadNegative.ts, 43, 12)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 43, 35)) +>o4 : Symbol(o4, Decl(objectSpreadNegative.ts, 33, 3)) + // primitives are not allowed, except for falsy ones let spreadNum = { ...12 }; ->spreadNum : Symbol(spreadNum, Decl(objectSpreadNegative.ts, 31, 3)) +>spreadNum : Symbol(spreadNum, Decl(objectSpreadNegative.ts, 46, 3)) let spreadSum = { ...1 + 1 }; ->spreadSum : Symbol(spreadSum, Decl(objectSpreadNegative.ts, 32, 3)) +>spreadSum : Symbol(spreadSum, Decl(objectSpreadNegative.ts, 47, 3)) let spreadZero = { ...0 }; ->spreadZero : Symbol(spreadZero, Decl(objectSpreadNegative.ts, 33, 3)) +>spreadZero : Symbol(spreadZero, Decl(objectSpreadNegative.ts, 48, 3)) spreadZero.toFixed(); // error, no methods even from a falsy number ->spreadZero : Symbol(spreadZero, Decl(objectSpreadNegative.ts, 33, 3)) +>spreadZero : Symbol(spreadZero, Decl(objectSpreadNegative.ts, 48, 3)) let spreadBool = { ...true }; ->spreadBool : Symbol(spreadBool, Decl(objectSpreadNegative.ts, 35, 3)) +>spreadBool : Symbol(spreadBool, Decl(objectSpreadNegative.ts, 50, 3)) spreadBool.valueOf(); ->spreadBool : Symbol(spreadBool, Decl(objectSpreadNegative.ts, 35, 3)) +>spreadBool : Symbol(spreadBool, Decl(objectSpreadNegative.ts, 50, 3)) let spreadStr = { ...'foo' }; ->spreadStr : Symbol(spreadStr, Decl(objectSpreadNegative.ts, 37, 3)) +>spreadStr : Symbol(spreadStr, Decl(objectSpreadNegative.ts, 52, 3)) spreadStr.length; // error, no 'length' ->spreadStr : Symbol(spreadStr, Decl(objectSpreadNegative.ts, 37, 3)) +>spreadStr : Symbol(spreadStr, Decl(objectSpreadNegative.ts, 52, 3)) spreadStr.charAt(1); // error, no methods either ->spreadStr : Symbol(spreadStr, Decl(objectSpreadNegative.ts, 37, 3)) +>spreadStr : Symbol(spreadStr, Decl(objectSpreadNegative.ts, 52, 3)) // functions are skipped let spreadFunc = { ...function () { } } ->spreadFunc : Symbol(spreadFunc, Decl(objectSpreadNegative.ts, 41, 3)) +>spreadFunc : Symbol(spreadFunc, Decl(objectSpreadNegative.ts, 56, 3)) spreadFunc(); // error, no call signature ->spreadFunc : Symbol(spreadFunc, Decl(objectSpreadNegative.ts, 41, 3)) +>spreadFunc : Symbol(spreadFunc, Decl(objectSpreadNegative.ts, 56, 3)) // write-only properties get skipped let setterOnly = { ...{ set b (bad: number) { } } }; ->setterOnly : Symbol(setterOnly, Decl(objectSpreadNegative.ts, 45, 3)) ->b : Symbol(b, Decl(objectSpreadNegative.ts, 45, 23)) ->bad : Symbol(bad, Decl(objectSpreadNegative.ts, 45, 31)) +>setterOnly : Symbol(setterOnly, Decl(objectSpreadNegative.ts, 60, 3)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 60, 23)) +>bad : Symbol(bad, Decl(objectSpreadNegative.ts, 60, 31)) setterOnly.b = 12; // error, 'b' does not exist ->setterOnly : Symbol(setterOnly, Decl(objectSpreadNegative.ts, 45, 3)) +>setterOnly : Symbol(setterOnly, Decl(objectSpreadNegative.ts, 60, 3)) // methods are skipped because they aren't enumerable class C { p = 1; m() { } } ->C : Symbol(C, Decl(objectSpreadNegative.ts, 46, 18)) ->p : Symbol(C.p, Decl(objectSpreadNegative.ts, 49, 9)) ->m : Symbol(C.m, Decl(objectSpreadNegative.ts, 49, 16)) +>C : Symbol(C, Decl(objectSpreadNegative.ts, 61, 18)) +>p : Symbol(C.p, Decl(objectSpreadNegative.ts, 64, 9)) +>m : Symbol(C.m, Decl(objectSpreadNegative.ts, 64, 16)) let c: C = new C() ->c : Symbol(c, Decl(objectSpreadNegative.ts, 50, 3)) ->C : Symbol(C, Decl(objectSpreadNegative.ts, 46, 18)) ->C : Symbol(C, Decl(objectSpreadNegative.ts, 46, 18)) +>c : Symbol(c, Decl(objectSpreadNegative.ts, 65, 3)) +>C : Symbol(C, Decl(objectSpreadNegative.ts, 61, 18)) +>C : Symbol(C, Decl(objectSpreadNegative.ts, 61, 18)) let spreadC = { ...c } ->spreadC : Symbol(spreadC, Decl(objectSpreadNegative.ts, 51, 3)) ->c : Symbol(c, Decl(objectSpreadNegative.ts, 50, 3)) +>spreadC : Symbol(spreadC, Decl(objectSpreadNegative.ts, 66, 3)) +>c : Symbol(c, Decl(objectSpreadNegative.ts, 65, 3)) spreadC.m(); // error 'm' is not in '{ ... c }' ->spreadC : Symbol(spreadC, Decl(objectSpreadNegative.ts, 51, 3)) +>spreadC : Symbol(spreadC, Decl(objectSpreadNegative.ts, 66, 3)) // non primitive let obj: object = { a: 123 }; ->obj : Symbol(obj, Decl(objectSpreadNegative.ts, 55, 3)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 55, 19)) +>obj : Symbol(obj, Decl(objectSpreadNegative.ts, 70, 3)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 70, 19)) let spreadObj = { ...obj }; ->spreadObj : Symbol(spreadObj, Decl(objectSpreadNegative.ts, 56, 3)) ->obj : Symbol(obj, Decl(objectSpreadNegative.ts, 55, 3)) +>spreadObj : Symbol(spreadObj, Decl(objectSpreadNegative.ts, 71, 3)) +>obj : Symbol(obj, Decl(objectSpreadNegative.ts, 70, 3)) spreadObj.a; // error 'a' is not in {} ->spreadObj : Symbol(spreadObj, Decl(objectSpreadNegative.ts, 56, 3)) +>spreadObj : Symbol(spreadObj, Decl(objectSpreadNegative.ts, 71, 3)) // generics function f(t: T, u: U) { ->f : Symbol(f, Decl(objectSpreadNegative.ts, 57, 12)) ->T : Symbol(T, Decl(objectSpreadNegative.ts, 60, 11)) ->U : Symbol(U, Decl(objectSpreadNegative.ts, 60, 13)) ->t : Symbol(t, Decl(objectSpreadNegative.ts, 60, 17)) ->T : Symbol(T, Decl(objectSpreadNegative.ts, 60, 11)) ->u : Symbol(u, Decl(objectSpreadNegative.ts, 60, 22)) ->U : Symbol(U, Decl(objectSpreadNegative.ts, 60, 13)) +>f : Symbol(f, Decl(objectSpreadNegative.ts, 72, 12)) +>T : Symbol(T, Decl(objectSpreadNegative.ts, 75, 11)) +>U : Symbol(U, Decl(objectSpreadNegative.ts, 75, 13)) +>t : Symbol(t, Decl(objectSpreadNegative.ts, 75, 17)) +>T : Symbol(T, Decl(objectSpreadNegative.ts, 75, 11)) +>u : Symbol(u, Decl(objectSpreadNegative.ts, 75, 22)) +>U : Symbol(U, Decl(objectSpreadNegative.ts, 75, 13)) return { ...t, ...u, id: 'id' }; ->t : Symbol(t, Decl(objectSpreadNegative.ts, 60, 17)) ->u : Symbol(u, Decl(objectSpreadNegative.ts, 60, 22)) ->id : Symbol(id, Decl(objectSpreadNegative.ts, 61, 24)) +>t : Symbol(t, Decl(objectSpreadNegative.ts, 75, 17)) +>u : Symbol(u, Decl(objectSpreadNegative.ts, 75, 22)) +>id : Symbol(id, Decl(objectSpreadNegative.ts, 76, 24)) } function override(initial: U, override: U): U { ->override : Symbol(override, Decl(objectSpreadNegative.ts, 62, 1)) ->U : Symbol(U, Decl(objectSpreadNegative.ts, 63, 18)) ->initial : Symbol(initial, Decl(objectSpreadNegative.ts, 63, 21)) ->U : Symbol(U, Decl(objectSpreadNegative.ts, 63, 18)) ->override : Symbol(override, Decl(objectSpreadNegative.ts, 63, 32)) ->U : Symbol(U, Decl(objectSpreadNegative.ts, 63, 18)) ->U : Symbol(U, Decl(objectSpreadNegative.ts, 63, 18)) +>override : Symbol(override, Decl(objectSpreadNegative.ts, 77, 1)) +>U : Symbol(U, Decl(objectSpreadNegative.ts, 78, 18)) +>initial : Symbol(initial, Decl(objectSpreadNegative.ts, 78, 21)) +>U : Symbol(U, Decl(objectSpreadNegative.ts, 78, 18)) +>override : Symbol(override, Decl(objectSpreadNegative.ts, 78, 32)) +>U : Symbol(U, Decl(objectSpreadNegative.ts, 78, 18)) +>U : Symbol(U, Decl(objectSpreadNegative.ts, 78, 18)) return { ...initial, ...override }; ->initial : Symbol(initial, Decl(objectSpreadNegative.ts, 63, 21)) ->override : Symbol(override, Decl(objectSpreadNegative.ts, 63, 32)) +>initial : Symbol(initial, Decl(objectSpreadNegative.ts, 78, 21)) +>override : Symbol(override, Decl(objectSpreadNegative.ts, 78, 32)) } let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = ->exclusive : Symbol(exclusive, Decl(objectSpreadNegative.ts, 66, 3)) ->id : Symbol(id, Decl(objectSpreadNegative.ts, 66, 16)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 66, 28)) ->b : Symbol(b, Decl(objectSpreadNegative.ts, 66, 39)) ->c : Symbol(c, Decl(objectSpreadNegative.ts, 66, 50)) ->d : Symbol(d, Decl(objectSpreadNegative.ts, 66, 61)) +>exclusive : Symbol(exclusive, Decl(objectSpreadNegative.ts, 81, 3)) +>id : Symbol(id, Decl(objectSpreadNegative.ts, 81, 16)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 81, 28)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 81, 39)) +>c : Symbol(c, Decl(objectSpreadNegative.ts, 81, 50)) +>d : Symbol(d, Decl(objectSpreadNegative.ts, 81, 61)) f({ a: 1, b: 'yes' }, { c: 'no', d: false }) ->f : Symbol(f, Decl(objectSpreadNegative.ts, 57, 12)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 67, 7)) ->b : Symbol(b, Decl(objectSpreadNegative.ts, 67, 13)) ->c : Symbol(c, Decl(objectSpreadNegative.ts, 67, 27)) ->d : Symbol(d, Decl(objectSpreadNegative.ts, 67, 36)) +>f : Symbol(f, Decl(objectSpreadNegative.ts, 72, 12)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 82, 7)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 82, 13)) +>c : Symbol(c, Decl(objectSpreadNegative.ts, 82, 27)) +>d : Symbol(d, Decl(objectSpreadNegative.ts, 82, 36)) let overlap: { id: string, a: number, b: string } = ->overlap : Symbol(overlap, Decl(objectSpreadNegative.ts, 68, 3)) ->id : Symbol(id, Decl(objectSpreadNegative.ts, 68, 14)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 68, 26)) ->b : Symbol(b, Decl(objectSpreadNegative.ts, 68, 37)) +>overlap : Symbol(overlap, Decl(objectSpreadNegative.ts, 83, 3)) +>id : Symbol(id, Decl(objectSpreadNegative.ts, 83, 14)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 83, 26)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 83, 37)) f({ a: 1 }, { a: 2, b: 'extra' }) ->f : Symbol(f, Decl(objectSpreadNegative.ts, 57, 12)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 69, 7)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 69, 17)) ->b : Symbol(b, Decl(objectSpreadNegative.ts, 69, 23)) +>f : Symbol(f, Decl(objectSpreadNegative.ts, 72, 12)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 84, 7)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 84, 17)) +>b : Symbol(b, Decl(objectSpreadNegative.ts, 84, 23)) let overlapConflict: { id:string, a: string } = ->overlapConflict : Symbol(overlapConflict, Decl(objectSpreadNegative.ts, 70, 3)) ->id : Symbol(id, Decl(objectSpreadNegative.ts, 70, 22)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 70, 33)) +>overlapConflict : Symbol(overlapConflict, Decl(objectSpreadNegative.ts, 85, 3)) +>id : Symbol(id, Decl(objectSpreadNegative.ts, 85, 22)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 85, 33)) f({ a: 1 }, { a: 'mismatch' }) ->f : Symbol(f, Decl(objectSpreadNegative.ts, 57, 12)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 71, 7)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 71, 17)) +>f : Symbol(f, Decl(objectSpreadNegative.ts, 72, 12)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 86, 7)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 86, 17)) let overwriteId: { id: string, a: number, c: number, d: string } = ->overwriteId : Symbol(overwriteId, Decl(objectSpreadNegative.ts, 72, 3)) ->id : Symbol(id, Decl(objectSpreadNegative.ts, 72, 18)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 72, 30)) ->c : Symbol(c, Decl(objectSpreadNegative.ts, 72, 41)) ->d : Symbol(d, Decl(objectSpreadNegative.ts, 72, 52)) +>overwriteId : Symbol(overwriteId, Decl(objectSpreadNegative.ts, 87, 3)) +>id : Symbol(id, Decl(objectSpreadNegative.ts, 87, 18)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 87, 30)) +>c : Symbol(c, Decl(objectSpreadNegative.ts, 87, 41)) +>d : Symbol(d, Decl(objectSpreadNegative.ts, 87, 52)) f({ a: 1, id: true }, { c: 1, d: 'no' }) ->f : Symbol(f, Decl(objectSpreadNegative.ts, 57, 12)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 73, 7)) ->id : Symbol(id, Decl(objectSpreadNegative.ts, 73, 13)) ->c : Symbol(c, Decl(objectSpreadNegative.ts, 73, 27)) ->d : Symbol(d, Decl(objectSpreadNegative.ts, 73, 33)) +>f : Symbol(f, Decl(objectSpreadNegative.ts, 72, 12)) +>a : Symbol(a, Decl(objectSpreadNegative.ts, 88, 7)) +>id : Symbol(id, Decl(objectSpreadNegative.ts, 88, 13)) +>c : Symbol(c, Decl(objectSpreadNegative.ts, 88, 27)) +>d : Symbol(d, Decl(objectSpreadNegative.ts, 88, 33)) diff --git a/tests/baselines/reference/objectSpreadNegative.types b/tests/baselines/reference/objectSpreadNegative.types index 26fd5642d2301..e56984f7c3e9f 100644 --- a/tests/baselines/reference/objectSpreadNegative.types +++ b/tests/baselines/reference/objectSpreadNegative.types @@ -90,7 +90,6 @@ spread = b; // error, missing 's' >spread : { s: string; b: boolean; } >b : { b: boolean; } -// literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } >duplicated : { b: string; a: number; } >{ b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } : { b: string; a: number; } @@ -109,6 +108,113 @@ let duplicatedSpread = { ...o, ...o } >o : { a: number; b: string; } >o : { a: number; b: string; } +// Note: ignore changes the order that properties are printed +let ignore: { a: number, b: string } = +>ignore : { a: number; b: string; } +>a : number +>b : string + + { b: 'ignored', ...o } +>{ b: 'ignored', ...o } : { a: number; b: string; } +>b : string +>'ignored' : "ignored" +>o : { a: number; b: string; } + +let o3 = { a: 1, b: 'no' } +>o3 : { a: number; b: string; } +>{ a: 1, b: 'no' } : { a: number; b: string; } +>a : number +>1 : 1 +>b : string +>'no' : "no" + +let o4 = { b: 'yes', c: true } +>o4 : { b: string; c: boolean; } +>{ b: 'yes', c: true } : { b: string; c: boolean; } +>b : string +>'yes' : "yes" +>c : boolean +>true : true + +let combinedBefore: { a: number, b: string, c: boolean } = +>combinedBefore : { a: number; b: string; c: boolean; } +>a : number +>b : string +>c : boolean + + { b: 'ok', ...o3, ...o4 } +>{ b: 'ok', ...o3, ...o4 } : { b: string; c: boolean; a: number; } +>b : string +>'ok' : "ok" +>o3 : { a: number; b: string; } +>o4 : { b: string; c: boolean; } + +let combinedMid: { a: number, b: string, c: boolean } = +>combinedMid : { a: number; b: string; c: boolean; } +>a : number +>b : string +>c : boolean + + { ...o3, b: 'ok', ...o4 } +>{ ...o3, b: 'ok', ...o4 } : { b: string; c: boolean; a: number; } +>o3 : { a: number; b: string; } +>b : string +>'ok' : "ok" +>o4 : { b: string; c: boolean; } + +let combinedNested: { a: number, b: boolean, c: string, d: string } = +>combinedNested : { a: number; b: boolean; c: string; d: string; } +>a : number +>b : boolean +>c : string +>d : string + + { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } +>{ ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } : { a: number; d: string; b: false; c: string; } +>{ a: 4, ...{ b: false, c: 'overriden' } } : { b: false; c: string; a: number; } +>a : number +>4 : 4 +>{ b: false, c: 'overriden' } : { b: false; c: string; } +>b : false +>false : false +>c : string +>'overriden' : "overriden" +>d : string +>'actually new' : "actually new" +>{ a: 5, d: 'maybe new' } : { a: number; d: string; } +>a : number +>5 : 5 +>d : string +>'maybe new' : "maybe new" + +let changeTypeBefore: { a: number, b: string } = +>changeTypeBefore : { a: number; b: string; } +>a : number +>b : string + + { a: 'wrong type?', ...o3 }; +>{ a: 'wrong type?', ...o3 } : { a: number; b: string; } +>a : string +>'wrong type?' : "wrong type?" +>o3 : { a: number; b: string; } + +let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = +>computedMiddle : { a: number; b: string; c: boolean; "in the middle": number; } +>a : number +>b : string +>c : boolean +>"in the middle" : number + + { ...o3, ['in the middle']: 13, b: 'maybe?', ...o4 } +>{ ...o3, ['in the middle']: 13, b: 'maybe?', ...o4 } : { b: string; c: boolean; ['in the middle']: number; a: number; } +>o3 : { a: number; b: string; } +>['in the middle'] : number +>'in the middle' : "in the middle" +>13 : 13 +>b : string +>'maybe?' : "maybe?" +>o4 : { b: string; c: boolean; } + // primitives are not allowed, except for falsy ones let spreadNum = { ...12 }; >spreadNum : any diff --git a/tests/baselines/reference/spreadOverwritesProperty.errors.txt b/tests/baselines/reference/spreadOverwritesProperty.errors.txt new file mode 100644 index 0000000000000..a6b78900b4815 --- /dev/null +++ b/tests/baselines/reference/spreadOverwritesProperty.errors.txt @@ -0,0 +1,12 @@ +tests/cases/conformance/types/spread/spreadOverwritesProperty.ts(3,17): error TS2735: 'b' is overwritten by a later spread. + + +==== tests/cases/conformance/types/spread/spreadOverwritesProperty.ts (1 errors) ==== + declare var ab: { a: number, b: number }; + declare var abq: { a: number, b?: number }; + var unused1 = { b: 1, ...ab } + ~~~~ +!!! error TS2735: 'b' is overwritten by a later spread. + var unused2 = { ...ab, ...ab } + var unused3 = { b: 1, ...abq } + \ No newline at end of file diff --git a/tests/baselines/reference/spreadOverwritesProperty.js b/tests/baselines/reference/spreadOverwritesProperty.js new file mode 100644 index 0000000000000..ac28594c4b1c3 --- /dev/null +++ b/tests/baselines/reference/spreadOverwritesProperty.js @@ -0,0 +1,23 @@ +//// [spreadOverwritesProperty.ts] +declare var ab: { a: number, b: number }; +declare var abq: { a: number, b?: number }; +var unused1 = { b: 1, ...ab } +var unused2 = { ...ab, ...ab } +var unused3 = { b: 1, ...abq } + + +//// [spreadOverwritesProperty.js] +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var unused1 = __assign({ b: 1 }, ab); +var unused2 = __assign({}, ab, ab); +var unused3 = __assign({ b: 1 }, abq); diff --git a/tests/baselines/reference/spreadOverwritesProperty.symbols b/tests/baselines/reference/spreadOverwritesProperty.symbols new file mode 100644 index 0000000000000..599a40c85536f --- /dev/null +++ b/tests/baselines/reference/spreadOverwritesProperty.symbols @@ -0,0 +1,26 @@ +=== tests/cases/conformance/types/spread/spreadOverwritesProperty.ts === +declare var ab: { a: number, b: number }; +>ab : Symbol(ab, Decl(spreadOverwritesProperty.ts, 0, 11)) +>a : Symbol(a, Decl(spreadOverwritesProperty.ts, 0, 17)) +>b : Symbol(b, Decl(spreadOverwritesProperty.ts, 0, 28)) + +declare var abq: { a: number, b?: number }; +>abq : Symbol(abq, Decl(spreadOverwritesProperty.ts, 1, 11)) +>a : Symbol(a, Decl(spreadOverwritesProperty.ts, 1, 18)) +>b : Symbol(b, Decl(spreadOverwritesProperty.ts, 1, 29)) + +var unused1 = { b: 1, ...ab } +>unused1 : Symbol(unused1, Decl(spreadOverwritesProperty.ts, 2, 3)) +>b : Symbol(b, Decl(spreadOverwritesProperty.ts, 2, 15)) +>ab : Symbol(ab, Decl(spreadOverwritesProperty.ts, 0, 11)) + +var unused2 = { ...ab, ...ab } +>unused2 : Symbol(unused2, Decl(spreadOverwritesProperty.ts, 3, 3)) +>ab : Symbol(ab, Decl(spreadOverwritesProperty.ts, 0, 11)) +>ab : Symbol(ab, Decl(spreadOverwritesProperty.ts, 0, 11)) + +var unused3 = { b: 1, ...abq } +>unused3 : Symbol(unused3, Decl(spreadOverwritesProperty.ts, 4, 3)) +>b : Symbol(b, Decl(spreadOverwritesProperty.ts, 4, 15)) +>abq : Symbol(abq, Decl(spreadOverwritesProperty.ts, 1, 11)) + diff --git a/tests/baselines/reference/spreadOverwritesProperty.types b/tests/baselines/reference/spreadOverwritesProperty.types new file mode 100644 index 0000000000000..9d6630a406563 --- /dev/null +++ b/tests/baselines/reference/spreadOverwritesProperty.types @@ -0,0 +1,31 @@ +=== tests/cases/conformance/types/spread/spreadOverwritesProperty.ts === +declare var ab: { a: number, b: number }; +>ab : { a: number; b: number; } +>a : number +>b : number + +declare var abq: { a: number, b?: number }; +>abq : { a: number; b?: number; } +>a : number +>b : number + +var unused1 = { b: 1, ...ab } +>unused1 : { a: number; b: number; } +>{ b: 1, ...ab } : { a: number; b: number; } +>b : number +>1 : 1 +>ab : { a: number; b: number; } + +var unused2 = { ...ab, ...ab } +>unused2 : { a: number; b: number; } +>{ ...ab, ...ab } : { a: number; b: number; } +>ab : { a: number; b: number; } +>ab : { a: number; b: number; } + +var unused3 = { b: 1, ...abq } +>unused3 : { a: number; b: number; } +>{ b: 1, ...abq } : { a: number; b: number; } +>b : number +>1 : 1 +>abq : { a: number; b?: number; } + diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt b/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt new file mode 100644 index 0000000000000..5a3706479afcd --- /dev/null +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt @@ -0,0 +1,12 @@ +tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(3,17): error TS2735: 'b' is overwritten by a later spread. + + +==== tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts (1 errors) ==== + declare var ab: { a: number, b: number }; + declare var abq: { a: number, b?: number }; + var unused1 = { b: 1, ...ab } + ~~~~ +!!! error TS2735: 'b' is overwritten by a later spread. + var unused2 = { ...ab, ...ab } + var unused3 = { b: 1, ...abq } + \ No newline at end of file diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.js b/tests/baselines/reference/spreadOverwritesPropertyStrict.js new file mode 100644 index 0000000000000..0767afcb586db --- /dev/null +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.js @@ -0,0 +1,24 @@ +//// [spreadOverwritesPropertyStrict.ts] +declare var ab: { a: number, b: number }; +declare var abq: { a: number, b?: number }; +var unused1 = { b: 1, ...ab } +var unused2 = { ...ab, ...ab } +var unused3 = { b: 1, ...abq } + + +//// [spreadOverwritesPropertyStrict.js] +"use strict"; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var unused1 = __assign({ b: 1 }, ab); +var unused2 = __assign({}, ab, ab); +var unused3 = __assign({ b: 1 }, abq); diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols b/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols new file mode 100644 index 0000000000000..0f03d28fdc86c --- /dev/null +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols @@ -0,0 +1,26 @@ +=== tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts === +declare var ab: { a: number, b: number }; +>ab : Symbol(ab, Decl(spreadOverwritesPropertyStrict.ts, 0, 11)) +>a : Symbol(a, Decl(spreadOverwritesPropertyStrict.ts, 0, 17)) +>b : Symbol(b, Decl(spreadOverwritesPropertyStrict.ts, 0, 28)) + +declare var abq: { a: number, b?: number }; +>abq : Symbol(abq, Decl(spreadOverwritesPropertyStrict.ts, 1, 11)) +>a : Symbol(a, Decl(spreadOverwritesPropertyStrict.ts, 1, 18)) +>b : Symbol(b, Decl(spreadOverwritesPropertyStrict.ts, 1, 29)) + +var unused1 = { b: 1, ...ab } +>unused1 : Symbol(unused1, Decl(spreadOverwritesPropertyStrict.ts, 2, 3)) +>b : Symbol(b, Decl(spreadOverwritesPropertyStrict.ts, 2, 15)) +>ab : Symbol(ab, Decl(spreadOverwritesPropertyStrict.ts, 0, 11)) + +var unused2 = { ...ab, ...ab } +>unused2 : Symbol(unused2, Decl(spreadOverwritesPropertyStrict.ts, 3, 3)) +>ab : Symbol(ab, Decl(spreadOverwritesPropertyStrict.ts, 0, 11)) +>ab : Symbol(ab, Decl(spreadOverwritesPropertyStrict.ts, 0, 11)) + +var unused3 = { b: 1, ...abq } +>unused3 : Symbol(unused3, Decl(spreadOverwritesPropertyStrict.ts, 4, 3)) +>b : Symbol(b, Decl(spreadOverwritesPropertyStrict.ts, 4, 15)) +>abq : Symbol(abq, Decl(spreadOverwritesPropertyStrict.ts, 1, 11)) + diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.types b/tests/baselines/reference/spreadOverwritesPropertyStrict.types new file mode 100644 index 0000000000000..f5a5492727757 --- /dev/null +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.types @@ -0,0 +1,31 @@ +=== tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts === +declare var ab: { a: number, b: number }; +>ab : { a: number; b: number; } +>a : number +>b : number + +declare var abq: { a: number, b?: number }; +>abq : { a: number; b?: number | undefined; } +>a : number +>b : number | undefined + +var unused1 = { b: 1, ...ab } +>unused1 : { a: number; b: number; } +>{ b: 1, ...ab } : { a: number; b: number; } +>b : number +>1 : 1 +>ab : { a: number; b: number; } + +var unused2 = { ...ab, ...ab } +>unused2 : { a: number; b: number; } +>{ ...ab, ...ab } : { a: number; b: number; } +>ab : { a: number; b: number; } +>ab : { a: number; b: number; } + +var unused3 = { b: 1, ...abq } +>unused3 : { a: number; b: number; } +>{ b: 1, ...abq } : { a: number; b: number; } +>b : number +>1 : 1 +>abq : { a: number; b?: number | undefined; } + diff --git a/tests/baselines/reference/spreadUnion3.errors.txt b/tests/baselines/reference/spreadUnion3.errors.txt index 88aa12c708fb8..b9c7c186fef04 100644 --- a/tests/baselines/reference/spreadUnion3.errors.txt +++ b/tests/baselines/reference/spreadUnion3.errors.txt @@ -1,15 +1,18 @@ tests/cases/conformance/types/spread/spreadUnion3.ts(2,14): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/conformance/types/spread/spreadUnion3.ts(2,14): error TS2735: 'y' is overwritten by a later spread. tests/cases/conformance/types/spread/spreadUnion3.ts(9,23): error TS2339: Property 'a' does not exist on type '{}'. tests/cases/conformance/types/spread/spreadUnion3.ts(17,11): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/spreadUnion3.ts(18,11): error TS2698: Spread types may only be created from object types. -==== tests/cases/conformance/types/spread/spreadUnion3.ts (4 errors) ==== +==== tests/cases/conformance/types/spread/spreadUnion3.ts (5 errors) ==== function f(x: { y: string } | undefined): { y: string } { return { y: 123, ...x } // y: string | number ~ !!! error TS2322: Type 'number' is not assignable to type 'string'. !!! related TS6500 tests/cases/conformance/types/spread/spreadUnion3.ts:1:45: The expected type comes from property 'y' which is declared here on type '{ y: string; }' + ~~~~~~ +!!! error TS2735: 'y' is overwritten by a later spread. } f(undefined) diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index c7cf5e49eed05..31370dd575f08 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -8,23 +8,14 @@ let addAfter: { a: number, b: string, c: boolean } = { ...o, c: false } let addBefore: { a: number, b: string, c: boolean } = { c: false, ...o } -// Note: ignore still changes the order that properties are printed -let ignore: { a: number, b: string } = - { b: 'ignored', ...o } let override: { a: number, b: string } = { ...o, b: 'override' } let nested: { a: number, b: boolean, c: string } = { ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' } let combined: { a: number, b: string, c: boolean } = { ...o, ...o2 } -let combinedBefore: { a: number, b: string, c: boolean } = - { b: 'ok', ...o, ...o2 } -let combinedMid: { a: number, b: string, c: boolean } = - { ...o, b: 'ok', ...o2 } let combinedAfter: { a: number, b: string, c: boolean } = { ...o, ...o2, b: 'ok' } -let combinedNested: { a: number, b: boolean, c: string, d: string } = - { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } let combinedNestedChangeType: { a: number, b: boolean, c: number } = { ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } let propertyNested: { a: { a: number, b: string } } = @@ -92,8 +83,6 @@ cplus.plus(); // new field's type conflicting with existing field is OK let changeTypeAfter: { a: string, b: string } = { ...o, a: 'wrong type?' } -let changeTypeBefore: { a: number, b: string } = - { a: 'wrong type?', ...o }; let changeTypeBoth: { a: string, b: number } = { ...o, ...swap }; @@ -110,8 +99,6 @@ function container( // computed property let computedFirst: { a: number, b: string, "before everything": number } = { ['before everything']: 12, ...o, b: 'yes' } - let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = - { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } let computedAfter: { a: number, b: string, "at the end": number } = { ...o, b: 'yeah', ['at the end']: 14 } } diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index 789016762da37..534fcb02bd648 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -25,9 +25,24 @@ spread = { s: "foo" }; // error, missing 'b' let b = { b: false }; spread = b; // error, missing 's' -// literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } +// Note: ignore changes the order that properties are printed +let ignore: { a: number, b: string } = + { b: 'ignored', ...o } + +let o3 = { a: 1, b: 'no' } +let o4 = { b: 'yes', c: true } +let combinedBefore: { a: number, b: string, c: boolean } = + { b: 'ok', ...o3, ...o4 } +let combinedMid: { a: number, b: string, c: boolean } = + { ...o3, b: 'ok', ...o4 } +let combinedNested: { a: number, b: boolean, c: string, d: string } = + { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } +let changeTypeBefore: { a: number, b: string } = + { a: 'wrong type?', ...o3 }; +let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = + { ...o3, ['in the middle']: 13, b: 'maybe?', ...o4 } // primitives are not allowed, except for falsy ones let spreadNum = { ...12 }; diff --git a/tests/cases/conformance/types/spread/spreadOverwritesProperty.ts b/tests/cases/conformance/types/spread/spreadOverwritesProperty.ts new file mode 100644 index 0000000000000..e4407fd87e4e7 --- /dev/null +++ b/tests/cases/conformance/types/spread/spreadOverwritesProperty.ts @@ -0,0 +1,5 @@ +declare var ab: { a: number, b: number }; +declare var abq: { a: number, b?: number }; +var unused1 = { b: 1, ...ab } +var unused2 = { ...ab, ...ab } +var unused3 = { b: 1, ...abq } diff --git a/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts b/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts new file mode 100644 index 0000000000000..d1df11e49b536 --- /dev/null +++ b/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts @@ -0,0 +1,6 @@ +// @strict: true +declare var ab: { a: number, b: number }; +declare var abq: { a: number, b?: number }; +var unused1 = { b: 1, ...ab } +var unused2 = { ...ab, ...ab } +var unused3 = { b: 1, ...abq } From ed7a75b3797535d8a69c2b8d9e0d7d9185e3db30 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Fri, 12 Oct 2018 08:33:30 -0700 Subject: [PATCH 2/2] Quck and dirty fix for union problems Doesn't fix JSX problems --- src/compiler/checker.ts | 13 +++++--- .../checkJsxChildrenProperty13.errors.txt | 33 ------------------- .../checkJsxChildrenProperty2.errors.txt | 5 +-- .../reference/objectSpreadNegative.errors.txt | 23 +------------ .../spreadOverwritesProperty.errors.txt | 12 ------- .../reference/spreadOverwritesProperty.js | 13 ++++++++ .../spreadOverwritesProperty.symbols | 19 +++++++++++ .../reference/spreadOverwritesProperty.types | 23 +++++++++++++ .../spreadOverwritesPropertyStrict.errors.txt | 6 ++++ .../spreadOverwritesPropertyStrict.js | 12 +++++++ .../spreadOverwritesPropertyStrict.symbols | 19 +++++++++++ .../spreadOverwritesPropertyStrict.types | 23 +++++++++++++ .../reference/spreadUnion3.errors.txt | 5 +-- .../types/spread/spreadOverwritesProperty.ts | 7 ++++ .../spread/spreadOverwritesPropertyStrict.ts | 6 ++++ 15 files changed, 140 insertions(+), 79 deletions(-) delete mode 100644 tests/baselines/reference/checkJsxChildrenProperty13.errors.txt delete mode 100644 tests/baselines/reference/spreadOverwritesProperty.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 148345c8ef592..bd48701de4c71 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9806,7 +9806,7 @@ namespace ts { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, symbol: Symbol | undefined, typeFlags: TypeFlags, objectFlags: ObjectFlags): Type { + function getSpreadType(left: Type, right: Type, symbol: Symbol | undefined, typeFlags: TypeFlags, objectFlags: ObjectFlags, isUnion?: boolean): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } @@ -9820,10 +9820,10 @@ namespace ts { return left; } if (left.flags & TypeFlags.Union) { - return mapType(left, t => getSpreadType(t, right, symbol, typeFlags, objectFlags)); + return mapType(left, t => getSpreadType(t, right, symbol, typeFlags, objectFlags, isUnion)); } if (right.flags & TypeFlags.Union) { - return mapType(right, t => getSpreadType(left, t, symbol, typeFlags, objectFlags)); + return mapType(right, t => getSpreadType(left, t, symbol, typeFlags, objectFlags, true)); } if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)) { return left; @@ -9870,7 +9870,12 @@ namespace ts { result.nameType = leftProp.nameType; members.set(leftProp.escapedName, result); } - else if (symbol && shouldCheckAsExcessProperty(leftProp, symbol) && !shouldCheckAsExcessProperty(rightProp, symbol)) { + else if (strictNullChecks && + !isUnion && + symbol && + shouldCheckAsExcessProperty(leftProp, symbol) && + !shouldCheckAsExcessProperty(rightProp, symbol) && + !(getFalsyFlags(rightType) & TypeFlags.Nullable)) { error(leftProp.valueDeclaration, Diagnostics._0_is_overwritten_by_a_later_spread, unescapeLeadingUnderscores(leftProp.escapedName)); } } diff --git a/tests/baselines/reference/checkJsxChildrenProperty13.errors.txt b/tests/baselines/reference/checkJsxChildrenProperty13.errors.txt deleted file mode 100644 index d375a6e0c09ea..0000000000000 --- a/tests/baselines/reference/checkJsxChildrenProperty13.errors.txt +++ /dev/null @@ -1,33 +0,0 @@ -tests/cases/conformance/jsx/file.tsx(12,46): error TS2735: 'children' is overwritten by a later spread. - - -==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== - import React = require('react'); - - interface ButtonProp { - a: number, - b: string, - children: Button; - } - - class Button extends React.Component { - render() { - // Error children are specified twice - return ( - ~~~~~~~~~~~~~ -!!! error TS2735: 'children' is overwritten by a later spread. -
Hello World
-
); - } - } - - interface InnerButtonProp { - a: number - } - - class InnerButton extends React.Component { - render() { - return (); - } - } - \ No newline at end of file diff --git a/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt b/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt index 38f6fae2447a9..0282c566e4419 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt +++ b/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt @@ -1,6 +1,5 @@ tests/cases/conformance/jsx/file.tsx(14,10): error TS2322: Type '{ a: number; b: string; }' is not assignable to type 'Prop'. Property 'children' is missing in type '{ a: number; b: string; }'. -tests/cases/conformance/jsx/file.tsx(17,25): error TS2735: 'children' is overwritten by a later spread. tests/cases/conformance/jsx/file.tsx(31,6): error TS2322: Type '{ children: (Element | ((name: string) => Element))[]; a: number; b: string; }' is not assignable to type 'Prop'. Types of property 'children' are incompatible. Type '(Element | ((name: string) => Element))[]' is not assignable to type 'string | Element'. @@ -23,7 +22,7 @@ tests/cases/conformance/jsx/file.tsx(49,6): error TS2322: Type '{ children: Elem Property 'type' is missing in type 'Element[]'. -==== tests/cases/conformance/jsx/file.tsx (6 errors) ==== +==== tests/cases/conformance/jsx/file.tsx (5 errors) ==== import React = require('react'); interface Prop { @@ -44,8 +43,6 @@ tests/cases/conformance/jsx/file.tsx(49,6): error TS2322: Type '{ children: Elem let k0 = - ~~~~~~~~~~~~~~~~~ -!!! error TS2735: 'children' is overwritten by a later spread. hi hi hi! ; diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 57de2e1797d2b..0d6a58fe76676 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -5,15 +5,8 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(23,1): error TS2322 Property 'b' is missing in type '{ s: string; }'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,1): error TS2322: Type '{ b: boolean; }' is not assignable to type '{ s: string; b: boolean; }'. Property 's' is missing in type '{ b: boolean; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(27,20): error TS2735: 'b' is overwritten by a later spread. tests/cases/conformance/types/spread/objectSpreadNegative.ts(27,36): error TS2300: Duplicate identifier 'b'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(27,53): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(31,7): error TS2735: 'b' is overwritten by a later spread. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(36,7): error TS2735: 'b' is overwritten by a later spread. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(38,14): error TS2735: 'b' is overwritten by a later spread. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(40,53): error TS2735: 'd' is overwritten by a later spread. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(42,7): error TS2735: 'a' is overwritten by a later spread. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(44,37): error TS2735: 'b' is overwritten by a later spread. tests/cases/conformance/types/spread/objectSpreadNegative.ts(47,19): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegative.ts(48,19): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegative.ts(49,20): error TS2698: Spread types may only be created from object types. @@ -27,7 +20,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(77,14): error TS269 tests/cases/conformance/types/spread/objectSpreadNegative.ts(80,14): error TS2698: Spread types may only be created from object types. -==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (24 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (17 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -66,8 +59,6 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(80,14): error TS269 !!! error TS2322: Property 's' is missing in type '{ b: boolean; }'. let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } - ~~~~~~~~ -!!! error TS2735: 'b' is overwritten by a later spread. ~ !!! error TS2300: Duplicate identifier 'b'. ~ @@ -76,31 +67,19 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(80,14): error TS269 // Note: ignore changes the order that properties are printed let ignore: { a: number, b: string } = { b: 'ignored', ...o } - ~~~~~~~~~~~~ -!!! error TS2735: 'b' is overwritten by a later spread. let o3 = { a: 1, b: 'no' } let o4 = { b: 'yes', c: true } let combinedBefore: { a: number, b: string, c: boolean } = { b: 'ok', ...o3, ...o4 } - ~~~~~~~ -!!! error TS2735: 'b' is overwritten by a later spread. let combinedMid: { a: number, b: string, c: boolean } = { ...o3, b: 'ok', ...o4 } - ~~~~~~~ -!!! error TS2735: 'b' is overwritten by a later spread. 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 TS2735: 'd' is overwritten by a later spread. let changeTypeBefore: { a: number, b: string } = { a: 'wrong type?', ...o3 }; - ~~~~~~~~~~~~~~~~ -!!! error TS2735: 'a' is overwritten by a later spread. let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = { ...o3, ['in the middle']: 13, b: 'maybe?', ...o4 } - ~~~~~~~~~~~ -!!! error TS2735: 'b' is overwritten by a later spread. // primitives are not allowed, except for falsy ones let spreadNum = { ...12 }; diff --git a/tests/baselines/reference/spreadOverwritesProperty.errors.txt b/tests/baselines/reference/spreadOverwritesProperty.errors.txt deleted file mode 100644 index a6b78900b4815..0000000000000 --- a/tests/baselines/reference/spreadOverwritesProperty.errors.txt +++ /dev/null @@ -1,12 +0,0 @@ -tests/cases/conformance/types/spread/spreadOverwritesProperty.ts(3,17): error TS2735: 'b' is overwritten by a later spread. - - -==== tests/cases/conformance/types/spread/spreadOverwritesProperty.ts (1 errors) ==== - declare var ab: { a: number, b: number }; - declare var abq: { a: number, b?: number }; - var unused1 = { b: 1, ...ab } - ~~~~ -!!! error TS2735: 'b' is overwritten by a later spread. - var unused2 = { ...ab, ...ab } - var unused3 = { b: 1, ...abq } - \ No newline at end of file diff --git a/tests/baselines/reference/spreadOverwritesProperty.js b/tests/baselines/reference/spreadOverwritesProperty.js index ac28594c4b1c3..653bc11367527 100644 --- a/tests/baselines/reference/spreadOverwritesProperty.js +++ b/tests/baselines/reference/spreadOverwritesProperty.js @@ -4,6 +4,13 @@ declare var abq: { a: number, b?: number }; var unused1 = { b: 1, ...ab } var unused2 = { ...ab, ...ab } var unused3 = { b: 1, ...abq } + +function g(obj: { x: number | undefined }) { + return { x: 1, ...obj }; // should be allowed because of undefined +} +function h(obj: { x: number }) { + return { x: 1, ...obj }; // should be allowed because we don't know about undefined +} //// [spreadOverwritesProperty.js] @@ -21,3 +28,9 @@ var __assign = (this && this.__assign) || function () { var unused1 = __assign({ b: 1 }, ab); var unused2 = __assign({}, ab, ab); var unused3 = __assign({ b: 1 }, abq); +function g(obj) { + return __assign({ x: 1 }, obj); // should be allowed because of undefined +} +function h(obj) { + return __assign({ x: 1 }, obj); // should be allowed because we don't know about undefined +} diff --git a/tests/baselines/reference/spreadOverwritesProperty.symbols b/tests/baselines/reference/spreadOverwritesProperty.symbols index 599a40c85536f..7af75e14d3a4f 100644 --- a/tests/baselines/reference/spreadOverwritesProperty.symbols +++ b/tests/baselines/reference/spreadOverwritesProperty.symbols @@ -24,3 +24,22 @@ var unused3 = { b: 1, ...abq } >b : Symbol(b, Decl(spreadOverwritesProperty.ts, 4, 15)) >abq : Symbol(abq, Decl(spreadOverwritesProperty.ts, 1, 11)) +function g(obj: { x: number | undefined }) { +>g : Symbol(g, Decl(spreadOverwritesProperty.ts, 4, 30)) +>obj : Symbol(obj, Decl(spreadOverwritesProperty.ts, 6, 11)) +>x : Symbol(x, Decl(spreadOverwritesProperty.ts, 6, 17)) + + return { x: 1, ...obj }; // should be allowed because of undefined +>x : Symbol(x, Decl(spreadOverwritesProperty.ts, 7, 12)) +>obj : Symbol(obj, Decl(spreadOverwritesProperty.ts, 6, 11)) +} +function h(obj: { x: number }) { +>h : Symbol(h, Decl(spreadOverwritesProperty.ts, 8, 1)) +>obj : Symbol(obj, Decl(spreadOverwritesProperty.ts, 9, 11)) +>x : Symbol(x, Decl(spreadOverwritesProperty.ts, 9, 17)) + + return { x: 1, ...obj }; // should be allowed because we don't know about undefined +>x : Symbol(x, Decl(spreadOverwritesProperty.ts, 10, 12)) +>obj : Symbol(obj, Decl(spreadOverwritesProperty.ts, 9, 11)) +} + diff --git a/tests/baselines/reference/spreadOverwritesProperty.types b/tests/baselines/reference/spreadOverwritesProperty.types index 9d6630a406563..0dad333c3a512 100644 --- a/tests/baselines/reference/spreadOverwritesProperty.types +++ b/tests/baselines/reference/spreadOverwritesProperty.types @@ -29,3 +29,26 @@ var unused3 = { b: 1, ...abq } >1 : 1 >abq : { a: number; b?: number; } +function g(obj: { x: number | undefined }) { +>g : (obj: { x: number; }) => { x: number; } +>obj : { x: number; } +>x : number + + return { x: 1, ...obj }; // should be allowed because of undefined +>{ x: 1, ...obj } : { x: number; } +>x : number +>1 : 1 +>obj : { x: number; } +} +function h(obj: { x: number }) { +>h : (obj: { x: number; }) => { x: number; } +>obj : { x: number; } +>x : number + + return { x: 1, ...obj }; // should be allowed because we don't know about undefined +>{ x: 1, ...obj } : { x: number; } +>x : number +>1 : 1 +>obj : { x: number; } +} + diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt b/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt index 5a3706479afcd..70febf00869ee 100644 --- a/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt @@ -9,4 +9,10 @@ tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(3,17): er !!! error TS2735: 'b' is overwritten by a later spread. var unused2 = { ...ab, ...ab } var unused3 = { b: 1, ...abq } + function g(obj: { x: number | undefined }) { + return { x: 1, ...obj }; // should be allowed because of undefined + } + function f(obj: { x: number } | undefined) { + return { x: 1, ...obj }; + } \ No newline at end of file diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.js b/tests/baselines/reference/spreadOverwritesPropertyStrict.js index 0767afcb586db..457bc5ed7e01e 100644 --- a/tests/baselines/reference/spreadOverwritesPropertyStrict.js +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.js @@ -4,6 +4,12 @@ declare var abq: { a: number, b?: number }; var unused1 = { b: 1, ...ab } var unused2 = { ...ab, ...ab } var unused3 = { b: 1, ...abq } +function g(obj: { x: number | undefined }) { + return { x: 1, ...obj }; // should be allowed because of undefined +} +function f(obj: { x: number } | undefined) { + return { x: 1, ...obj }; +} //// [spreadOverwritesPropertyStrict.js] @@ -22,3 +28,9 @@ var __assign = (this && this.__assign) || function () { var unused1 = __assign({ b: 1 }, ab); var unused2 = __assign({}, ab, ab); var unused3 = __assign({ b: 1 }, abq); +function g(obj) { + return __assign({ x: 1 }, obj); // should be allowed because of undefined +} +function f(obj) { + return __assign({ x: 1 }, obj); +} diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols b/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols index 0f03d28fdc86c..0168d14296ffe 100644 --- a/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols @@ -24,3 +24,22 @@ var unused3 = { b: 1, ...abq } >b : Symbol(b, Decl(spreadOverwritesPropertyStrict.ts, 4, 15)) >abq : Symbol(abq, Decl(spreadOverwritesPropertyStrict.ts, 1, 11)) +function g(obj: { x: number | undefined }) { +>g : Symbol(g, Decl(spreadOverwritesPropertyStrict.ts, 4, 30)) +>obj : Symbol(obj, Decl(spreadOverwritesPropertyStrict.ts, 5, 11)) +>x : Symbol(x, Decl(spreadOverwritesPropertyStrict.ts, 5, 17)) + + return { x: 1, ...obj }; // should be allowed because of undefined +>x : Symbol(x, Decl(spreadOverwritesPropertyStrict.ts, 6, 12)) +>obj : Symbol(obj, Decl(spreadOverwritesPropertyStrict.ts, 5, 11)) +} +function f(obj: { x: number } | undefined) { +>f : Symbol(f, Decl(spreadOverwritesPropertyStrict.ts, 7, 1)) +>obj : Symbol(obj, Decl(spreadOverwritesPropertyStrict.ts, 8, 11)) +>x : Symbol(x, Decl(spreadOverwritesPropertyStrict.ts, 8, 17)) + + return { x: 1, ...obj }; +>x : Symbol(x, Decl(spreadOverwritesPropertyStrict.ts, 9, 12)) +>obj : Symbol(obj, Decl(spreadOverwritesPropertyStrict.ts, 8, 11)) +} + diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.types b/tests/baselines/reference/spreadOverwritesPropertyStrict.types index f5a5492727757..64350c3985a0e 100644 --- a/tests/baselines/reference/spreadOverwritesPropertyStrict.types +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.types @@ -29,3 +29,26 @@ var unused3 = { b: 1, ...abq } >1 : 1 >abq : { a: number; b?: number | undefined; } +function g(obj: { x: number | undefined }) { +>g : (obj: { x: number | undefined; }) => { x: number | undefined; } +>obj : { x: number | undefined; } +>x : number | undefined + + return { x: 1, ...obj }; // should be allowed because of undefined +>{ x: 1, ...obj } : { x: number | undefined; } +>x : number +>1 : 1 +>obj : { x: number | undefined; } +} +function f(obj: { x: number } | undefined) { +>f : (obj: { x: number; } | undefined) => { x: number; } | { x: number; } +>obj : { x: number; } | undefined +>x : number + + return { x: 1, ...obj }; +>{ x: 1, ...obj } : { x: number; } | { x: number; } +>x : number +>1 : 1 +>obj : { x: number; } | undefined +} + diff --git a/tests/baselines/reference/spreadUnion3.errors.txt b/tests/baselines/reference/spreadUnion3.errors.txt index b9c7c186fef04..88aa12c708fb8 100644 --- a/tests/baselines/reference/spreadUnion3.errors.txt +++ b/tests/baselines/reference/spreadUnion3.errors.txt @@ -1,18 +1,15 @@ tests/cases/conformance/types/spread/spreadUnion3.ts(2,14): error TS2322: Type 'number' is not assignable to type 'string'. -tests/cases/conformance/types/spread/spreadUnion3.ts(2,14): error TS2735: 'y' is overwritten by a later spread. tests/cases/conformance/types/spread/spreadUnion3.ts(9,23): error TS2339: Property 'a' does not exist on type '{}'. tests/cases/conformance/types/spread/spreadUnion3.ts(17,11): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/spreadUnion3.ts(18,11): error TS2698: Spread types may only be created from object types. -==== tests/cases/conformance/types/spread/spreadUnion3.ts (5 errors) ==== +==== tests/cases/conformance/types/spread/spreadUnion3.ts (4 errors) ==== function f(x: { y: string } | undefined): { y: string } { return { y: 123, ...x } // y: string | number ~ !!! error TS2322: Type 'number' is not assignable to type 'string'. !!! related TS6500 tests/cases/conformance/types/spread/spreadUnion3.ts:1:45: The expected type comes from property 'y' which is declared here on type '{ y: string; }' - ~~~~~~ -!!! error TS2735: 'y' is overwritten by a later spread. } f(undefined) diff --git a/tests/cases/conformance/types/spread/spreadOverwritesProperty.ts b/tests/cases/conformance/types/spread/spreadOverwritesProperty.ts index e4407fd87e4e7..4ebc7f9fa08ee 100644 --- a/tests/cases/conformance/types/spread/spreadOverwritesProperty.ts +++ b/tests/cases/conformance/types/spread/spreadOverwritesProperty.ts @@ -3,3 +3,10 @@ declare var abq: { a: number, b?: number }; var unused1 = { b: 1, ...ab } var unused2 = { ...ab, ...ab } var unused3 = { b: 1, ...abq } + +function g(obj: { x: number | undefined }) { + return { x: 1, ...obj }; // should be allowed because of undefined +} +function h(obj: { x: number }) { + return { x: 1, ...obj }; // should be allowed because we don't know about undefined +} diff --git a/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts b/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts index d1df11e49b536..e2bf6da240fac 100644 --- a/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts +++ b/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts @@ -4,3 +4,9 @@ declare var abq: { a: number, b?: number }; var unused1 = { b: 1, ...ab } var unused2 = { ...ab, ...ab } var unused3 = { b: 1, ...abq } +function g(obj: { x: number | undefined }) { + return { x: 1, ...obj }; // should be allowed because of undefined +} +function f(obj: { x: number } | undefined) { + return { x: 1, ...obj }; +}