From 27c8c840eda5c86c1b1333567bc41be10a31312a Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 22 Apr 2021 09:11:16 -0700 Subject: [PATCH 1/2] Add test --- tests/cases/compiler/destructuringFromUnionSpread.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/cases/compiler/destructuringFromUnionSpread.ts diff --git a/tests/cases/compiler/destructuringFromUnionSpread.ts b/tests/cases/compiler/destructuringFromUnionSpread.ts new file mode 100644 index 0000000000000..92ef2e369aa9b --- /dev/null +++ b/tests/cases/compiler/destructuringFromUnionSpread.ts @@ -0,0 +1,11 @@ +interface A { a: string } +interface B { b: number } + +function foo(x: A | B) { + const { a } = { ...x } // no error?! + // const a: string | undefined + a?.toUpperCase(); +} + +const x = { a: 1, b: 2 } +foo(x); // a.toUpperCase is not a function, oops From 2950db90ed7c84a310e5e7cca6b7771e56ead36e Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 22 Apr 2021 16:32:43 -0700 Subject: [PATCH 2/2] =?UTF-8?q?Don=E2=80=99t=20allow=20an=20object=20liter?= =?UTF-8?q?al=20with=20a=20spread=20as=20a=20fallback=20for=20destructurin?= =?UTF-8?q?g=20a=20property=20not=20present=20in=20all=20constituents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/compiler/checker.ts | 2 +- .../destructuringFromUnionSpread.errors.txt | 12 +++++++++++ .../reference/destructuringFromUnionSpread.js | 21 +++++++++++++++++++ .../destructuringFromUnionSpread.symbols | 18 ++++++++++++++++ .../destructuringFromUnionSpread.types | 15 +++++++++++++ .../compiler/destructuringFromUnionSpread.ts | 10 ++------- 6 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 tests/baselines/reference/destructuringFromUnionSpread.errors.txt create mode 100644 tests/baselines/reference/destructuringFromUnionSpread.js create mode 100644 tests/baselines/reference/destructuringFromUnionSpread.symbols create mode 100644 tests/baselines/reference/destructuringFromUnionSpread.types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3cc7ff57f8cba..750d3232987c8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11698,7 +11698,7 @@ namespace ts { checkFlags |= CheckFlags.WritePartial | (indexInfo.isReadonly ? CheckFlags.Readonly : 0); indexTypes = append(indexTypes, isTupleType(type) ? getRestTypeOfTupleType(type) || undefinedType : indexInfo.type); } - else if (isObjectLiteralType(type)) { + else if (isObjectLiteralType(type) && !(getObjectFlags(type) & ObjectFlags.ContainsSpread)) { checkFlags |= CheckFlags.WritePartial; indexTypes = append(indexTypes, undefinedType); } diff --git a/tests/baselines/reference/destructuringFromUnionSpread.errors.txt b/tests/baselines/reference/destructuringFromUnionSpread.errors.txt new file mode 100644 index 0000000000000..f329b8a8d38f0 --- /dev/null +++ b/tests/baselines/reference/destructuringFromUnionSpread.errors.txt @@ -0,0 +1,12 @@ +tests/cases/compiler/destructuringFromUnionSpread.ts(5,9): error TS2525: Initializer provides no value for this binding element and the binding element has no default value. + + +==== tests/cases/compiler/destructuringFromUnionSpread.ts (1 errors) ==== + interface A { a: string } + interface B { b: number } + + declare const x: A | B; + const { a } = { ...x } // error + ~ +!!! error TS2525: Initializer provides no value for this binding element and the binding element has no default value. + \ No newline at end of file diff --git a/tests/baselines/reference/destructuringFromUnionSpread.js b/tests/baselines/reference/destructuringFromUnionSpread.js new file mode 100644 index 0000000000000..a67e1a711260d --- /dev/null +++ b/tests/baselines/reference/destructuringFromUnionSpread.js @@ -0,0 +1,21 @@ +//// [destructuringFromUnionSpread.ts] +interface A { a: string } +interface B { b: number } + +declare const x: A | B; +const { a } = { ...x } // error + + +//// [destructuringFromUnionSpread.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 a = __assign({}, x).a; // error diff --git a/tests/baselines/reference/destructuringFromUnionSpread.symbols b/tests/baselines/reference/destructuringFromUnionSpread.symbols new file mode 100644 index 0000000000000..88737096bce93 --- /dev/null +++ b/tests/baselines/reference/destructuringFromUnionSpread.symbols @@ -0,0 +1,18 @@ +=== tests/cases/compiler/destructuringFromUnionSpread.ts === +interface A { a: string } +>A : Symbol(A, Decl(destructuringFromUnionSpread.ts, 0, 0)) +>a : Symbol(A.a, Decl(destructuringFromUnionSpread.ts, 0, 13)) + +interface B { b: number } +>B : Symbol(B, Decl(destructuringFromUnionSpread.ts, 0, 25)) +>b : Symbol(B.b, Decl(destructuringFromUnionSpread.ts, 1, 13)) + +declare const x: A | B; +>x : Symbol(x, Decl(destructuringFromUnionSpread.ts, 3, 13)) +>A : Symbol(A, Decl(destructuringFromUnionSpread.ts, 0, 0)) +>B : Symbol(B, Decl(destructuringFromUnionSpread.ts, 0, 25)) + +const { a } = { ...x } // error +>a : Symbol(a, Decl(destructuringFromUnionSpread.ts, 4, 7)) +>x : Symbol(x, Decl(destructuringFromUnionSpread.ts, 3, 13)) + diff --git a/tests/baselines/reference/destructuringFromUnionSpread.types b/tests/baselines/reference/destructuringFromUnionSpread.types new file mode 100644 index 0000000000000..e24656790e167 --- /dev/null +++ b/tests/baselines/reference/destructuringFromUnionSpread.types @@ -0,0 +1,15 @@ +=== tests/cases/compiler/destructuringFromUnionSpread.ts === +interface A { a: string } +>a : string + +interface B { b: number } +>b : number + +declare const x: A | B; +>x : A | B + +const { a } = { ...x } // error +>a : any +>{ ...x } : { a: any; } | { a: any; b: number; } +>x : A | B + diff --git a/tests/cases/compiler/destructuringFromUnionSpread.ts b/tests/cases/compiler/destructuringFromUnionSpread.ts index 92ef2e369aa9b..2e73fa6813443 100644 --- a/tests/cases/compiler/destructuringFromUnionSpread.ts +++ b/tests/cases/compiler/destructuringFromUnionSpread.ts @@ -1,11 +1,5 @@ interface A { a: string } interface B { b: number } -function foo(x: A | B) { - const { a } = { ...x } // no error?! - // const a: string | undefined - a?.toUpperCase(); -} - -const x = { a: 1, b: 2 } -foo(x); // a.toUpperCase is not a function, oops +declare const x: A | B; +const { a } = { ...x } // error