From 1236a1006c3d864fb8e09b6fd4ccb8caa601fb90 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 19 Feb 2020 08:28:12 -0800 Subject: [PATCH] Fix initialization error when destructuring from object literal that includes a spread assignment (#36865) * Add test * Fix superfluous error when destructuring from object that includes spread assignment * Update baseline to include error case * Remove redundant check --- src/compiler/checker.ts | 6 +- .../reference/destructuringSpread.errors.txt | 34 ++++++++ .../reference/destructuringSpread.js | 48 +++++++++++ .../reference/destructuringSpread.symbols | 60 +++++++++++++ .../reference/destructuringSpread.types | 84 +++++++++++++++++++ .../es6/destructuring/destructuringSpread.ts | 27 ++++++ 6 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/destructuringSpread.errors.txt create mode 100644 tests/baselines/reference/destructuringSpread.js create mode 100644 tests/baselines/reference/destructuringSpread.symbols create mode 100644 tests/baselines/reference/destructuringSpread.types create mode 100644 tests/cases/conformance/es6/destructuring/destructuringSpread.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0d7448ab650..dfa4b0e63e4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22546,9 +22546,11 @@ namespace ts { // If object literal is contextually typed by the implied type of a binding pattern, augment the result // type with those properties for which the binding pattern specifies a default value. - if (contextualTypeHasPattern) { + // If the object literal is spread into another object literal, skip this step and let the top-level object + // literal handle it instead. + if (contextualTypeHasPattern && node.parent.kind !== SyntaxKind.SpreadAssignment) { for (const prop of getPropertiesOfType(contextualType!)) { - if (!propertiesTable.get(prop.escapedName) && !(spread && getPropertyOfType(spread, prop.escapedName))) { + if (!propertiesTable.get(prop.escapedName) && !getPropertyOfType(spread, prop.escapedName)) { if (!(prop.flags & SymbolFlags.Optional)) { error(prop.valueDeclaration || (prop).bindingElement, Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value); diff --git a/tests/baselines/reference/destructuringSpread.errors.txt b/tests/baselines/reference/destructuringSpread.errors.txt new file mode 100644 index 00000000000..b9cd4a85d85 --- /dev/null +++ b/tests/baselines/reference/destructuringSpread.errors.txt @@ -0,0 +1,34 @@ +tests/cases/conformance/es6/destructuring/destructuringSpread.ts(16,21): error TS2525: Initializer provides no value for this binding element and the binding element has no default value. + + +==== tests/cases/conformance/es6/destructuring/destructuringSpread.ts (1 errors) ==== + const { x } = { + ...{}, + x: 0 + }; + + const { y } = { + y: 0, + ...{} + }; + + const { z, a, b } = { + z: 0, + ...{ a: 0, b: 0 } + }; + + const { c, d, e, f, g } = { + ~ +!!! error TS2525: Initializer provides no value for this binding element and the binding element has no default value. + ...{ + ...{ + ...{ + c: 0, + }, + d: 0 + }, + e: 0 + }, + f: 0 + }; + \ No newline at end of file diff --git a/tests/baselines/reference/destructuringSpread.js b/tests/baselines/reference/destructuringSpread.js new file mode 100644 index 00000000000..e5e146d0e34 --- /dev/null +++ b/tests/baselines/reference/destructuringSpread.js @@ -0,0 +1,48 @@ +//// [destructuringSpread.ts] +const { x } = { + ...{}, + x: 0 +}; + +const { y } = { + y: 0, + ...{} +}; + +const { z, a, b } = { + z: 0, + ...{ a: 0, b: 0 } +}; + +const { c, d, e, f, g } = { + ...{ + ...{ + ...{ + c: 0, + }, + d: 0 + }, + e: 0 + }, + f: 0 +}; + + +//// [destructuringSpread.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 x = __assign({}, { x: 0 }).x; +var y = __assign({ y: 0 }, {}).y; +var _a = __assign({ z: 0 }, { a: 0, b: 0 }), z = _a.z, a = _a.a, b = _a.b; +var _b = __assign(__assign({}, __assign(__assign({}, __assign({ + c: 0 +}, { d: 0 })), { e: 0 })), { f: 0 }), c = _b.c, d = _b.d, e = _b.e, f = _b.f, g = _b.g; diff --git a/tests/baselines/reference/destructuringSpread.symbols b/tests/baselines/reference/destructuringSpread.symbols new file mode 100644 index 00000000000..eaee771f3e1 --- /dev/null +++ b/tests/baselines/reference/destructuringSpread.symbols @@ -0,0 +1,60 @@ +=== tests/cases/conformance/es6/destructuring/destructuringSpread.ts === +const { x } = { +>x : Symbol(x, Decl(destructuringSpread.ts, 0, 7)) + + ...{}, + x: 0 +>x : Symbol(x, Decl(destructuringSpread.ts, 1, 8)) + +}; + +const { y } = { +>y : Symbol(y, Decl(destructuringSpread.ts, 5, 7)) + + y: 0, +>y : Symbol(y, Decl(destructuringSpread.ts, 5, 15)) + + ...{} +}; + +const { z, a, b } = { +>z : Symbol(z, Decl(destructuringSpread.ts, 10, 7)) +>a : Symbol(a, Decl(destructuringSpread.ts, 10, 10)) +>b : Symbol(b, Decl(destructuringSpread.ts, 10, 13)) + + z: 0, +>z : Symbol(z, Decl(destructuringSpread.ts, 10, 21)) + + ...{ a: 0, b: 0 } +>a : Symbol(a, Decl(destructuringSpread.ts, 12, 6)) +>b : Symbol(b, Decl(destructuringSpread.ts, 12, 12)) + +}; + +const { c, d, e, f, g } = { +>c : Symbol(c, Decl(destructuringSpread.ts, 15, 7)) +>d : Symbol(d, Decl(destructuringSpread.ts, 15, 10)) +>e : Symbol(e, Decl(destructuringSpread.ts, 15, 13)) +>f : Symbol(f, Decl(destructuringSpread.ts, 15, 16)) +>g : Symbol(g, Decl(destructuringSpread.ts, 15, 19)) + + ...{ + ...{ + ...{ + c: 0, +>c : Symbol(c, Decl(destructuringSpread.ts, 18, 10)) + + }, + d: 0 +>d : Symbol(d, Decl(destructuringSpread.ts, 20, 8)) + + }, + e: 0 +>e : Symbol(e, Decl(destructuringSpread.ts, 22, 6)) + + }, + f: 0 +>f : Symbol(f, Decl(destructuringSpread.ts, 24, 4)) + +}; + diff --git a/tests/baselines/reference/destructuringSpread.types b/tests/baselines/reference/destructuringSpread.types new file mode 100644 index 00000000000..14911b8b7f1 --- /dev/null +++ b/tests/baselines/reference/destructuringSpread.types @@ -0,0 +1,84 @@ +=== tests/cases/conformance/es6/destructuring/destructuringSpread.ts === +const { x } = { +>x : number +>{ ...{}, x: 0} : { x: number; } + + ...{}, +>{} : {} + + x: 0 +>x : number +>0 : 0 + +}; + +const { y } = { +>y : number +>{ y: 0, ...{}} : { y: number; } + + y: 0, +>y : number +>0 : 0 + + ...{} +>{} : {} + +}; + +const { z, a, b } = { +>z : number +>a : number +>b : number +>{ z: 0, ...{ a: 0, b: 0 }} : { a: number; b: number; z: number; } + + z: 0, +>z : number +>0 : 0 + + ...{ a: 0, b: 0 } +>{ a: 0, b: 0 } : { a: number; b: number; } +>a : number +>0 : 0 +>b : number +>0 : 0 + +}; + +const { c, d, e, f, g } = { +>c : number +>d : number +>e : number +>f : number +>g : any +>{ ...{ ...{ ...{ c: 0, }, d: 0 }, e: 0 }, f: 0} : { f: number; g: any; e: number; d: number; c: number; } + + ...{ +>{ ...{ ...{ c: 0, }, d: 0 }, e: 0 } : { e: number; d: number; c: number; } + + ...{ +>{ ...{ c: 0, }, d: 0 } : { d: number; c: number; } + + ...{ +>{ c: 0, } : { c: number; } + + c: 0, +>c : number +>0 : 0 + + }, + d: 0 +>d : number +>0 : 0 + + }, + e: 0 +>e : number +>0 : 0 + + }, + f: 0 +>f : number +>0 : 0 + +}; + diff --git a/tests/cases/conformance/es6/destructuring/destructuringSpread.ts b/tests/cases/conformance/es6/destructuring/destructuringSpread.ts new file mode 100644 index 00000000000..85904ab164a --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/destructuringSpread.ts @@ -0,0 +1,27 @@ +const { x } = { + ...{}, + x: 0 +}; + +const { y } = { + y: 0, + ...{} +}; + +const { z, a, b } = { + z: 0, + ...{ a: 0, b: 0 } +}; + +const { c, d, e, f, g } = { + ...{ + ...{ + ...{ + c: 0, + }, + d: 0 + }, + e: 0 + }, + f: 0 +};