From a7da9ebd3b5de1e0af35dccafb6104ac440ee38b Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 9 Apr 2018 17:58:34 -0700 Subject: [PATCH 1/2] Add support for destructuring well-known and late-bound names --- src/compiler/checker.ts | 9 ++++--- ...estructuredLateBoundNameHasCorrectTypes.js | 16 +++++++++++ ...cturedLateBoundNameHasCorrectTypes.symbols | 21 +++++++++++++++ ...ructuredLateBoundNameHasCorrectTypes.types | 27 +++++++++++++++++++ ...estructuredLateBoundNameHasCorrectTypes.ts | 8 ++++++ .../TypeScript-Node-Starter | 2 +- 6 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.js create mode 100644 tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.symbols create mode 100644 tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.types create mode 100644 tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5634e06d5fd2b..9e128db21aeb9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4174,14 +4174,17 @@ namespace ts { else { // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) const name = declaration.propertyName || declaration.name; - if (isComputedNonLiteralName(name)) { - // computed properties with non-literal names are treated as 'any' + const isLate = isLateBindableName(name); + const isWellKnown = isComputedPropertyName(name) && isWellKnownSymbolSyntactically(name.expression); + if (!isLate && !isWellKnown && isComputedNonLiteralName(name)) { return anyType; } // Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature, // or otherwise the type of the string index signature. - const text = getTextOfPropertyName(name); + const text = isLate ? getLateBoundNameFromType(checkComputedPropertyName(name as ComputedPropertyName) as LiteralType | UniqueESSymbolType) : + isWellKnown ? getPropertyNameForKnownSymbolName(idText(((name as ComputedPropertyName).expression as PropertyAccessExpression).name)) : + getTextOfPropertyName(name); // Relax null check on ambient destructuring parameters, since the parameters have no implementation and are just documentation if (strictNullChecks && declaration.flags & NodeFlags.Ambient && isParameterDeclaration(declaration)) { diff --git a/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.js b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.js new file mode 100644 index 0000000000000..771e8fa001326 --- /dev/null +++ b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.js @@ -0,0 +1,16 @@ +//// [destructuredLateBoundNameHasCorrectTypes.ts] +let { [Symbol.iterator]: destructured } = []; +void destructured; + +const named = "prop"; + +let { [named]: computed } = { prop: "b" }; +void computed; + + +//// [destructuredLateBoundNameHasCorrectTypes.js] +let { [Symbol.iterator]: destructured } = []; +void destructured; +const named = "prop"; +let { [named]: computed } = { prop: "b" }; +void computed; diff --git a/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.symbols b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.symbols new file mode 100644 index 0000000000000..876cd9faeefa1 --- /dev/null +++ b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.symbols @@ -0,0 +1,21 @@ +=== tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts === +let { [Symbol.iterator]: destructured } = []; +>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --)) +>Symbol : Symbol(Symbol, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --)) +>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --)) +>destructured : Symbol(destructured, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 0, 5)) + +void destructured; +>destructured : Symbol(destructured, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 0, 5)) + +const named = "prop"; +>named : Symbol(named, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 3, 5)) + +let { [named]: computed } = { prop: "b" }; +>named : Symbol(named, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 3, 5)) +>computed : Symbol(computed, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 5, 5)) +>prop : Symbol(prop, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 5, 29)) + +void computed; +>computed : Symbol(computed, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 5, 5)) + diff --git a/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.types b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.types new file mode 100644 index 0000000000000..db8e19a598630 --- /dev/null +++ b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.types @@ -0,0 +1,27 @@ +=== tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts === +let { [Symbol.iterator]: destructured } = []; +>Symbol.iterator : symbol +>Symbol : SymbolConstructor +>iterator : symbol +>destructured : () => IterableIterator +>[] : undefined[] + +void destructured; +>void destructured : undefined +>destructured : () => IterableIterator + +const named = "prop"; +>named : "prop" +>"prop" : "prop" + +let { [named]: computed } = { prop: "b" }; +>named : "prop" +>computed : string +>{ prop: "b" } : { prop: string; } +>prop : string +>"b" : "b" + +void computed; +>void computed : undefined +>computed : string + diff --git a/tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts b/tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts new file mode 100644 index 0000000000000..e112ec453b06e --- /dev/null +++ b/tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts @@ -0,0 +1,8 @@ +// @target: es6 +let { [Symbol.iterator]: destructured } = []; +void destructured; + +const named = "prop"; + +let { [named]: computed } = { prop: "b" }; +void computed; diff --git a/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter b/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter index ed149eb0c787b..40bdb4eadabc9 160000 --- a/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter +++ b/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter @@ -1 +1 @@ -Subproject commit ed149eb0c787b1195a95b44105822c64bb6eb636 +Subproject commit 40bdb4eadabc9fbed7d83e3f26817a931c0763b6 From 57ce92d57de63f9e9924c3f8906aa66093291201 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 10 Apr 2018 12:38:29 -0700 Subject: [PATCH 2/2] Add test of not present late bound prop --- ...uredLateBoundNameHasCorrectTypes.errors.txt | 18 ++++++++++++++++++ ...destructuredLateBoundNameHasCorrectTypes.js | 6 ++++++ ...ucturedLateBoundNameHasCorrectTypes.symbols | 8 ++++++++ ...tructuredLateBoundNameHasCorrectTypes.types | 11 +++++++++++ ...destructuredLateBoundNameHasCorrectTypes.ts | 4 ++++ 5 files changed, 47 insertions(+) create mode 100644 tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.errors.txt diff --git a/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.errors.txt b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.errors.txt new file mode 100644 index 0000000000000..6a5c50021db04 --- /dev/null +++ b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.errors.txt @@ -0,0 +1,18 @@ +tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts(11,7): error TS2459: Type '{ prop: string; }' has no property '[notPresent]' and no string index signature. + + +==== tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts (1 errors) ==== + let { [Symbol.iterator]: destructured } = []; + void destructured; + + const named = "prop"; + + let { [named]: computed } = { prop: "b" }; + void computed; + + const notPresent = "prop2"; + + let { [notPresent]: computed2 } = { prop: "b" }; + ~~~~~~~~~~~~ +!!! error TS2459: Type '{ prop: string; }' has no property '[notPresent]' and no string index signature. + \ No newline at end of file diff --git a/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.js b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.js index 771e8fa001326..b1bee839e9010 100644 --- a/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.js +++ b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.js @@ -6,6 +6,10 @@ const named = "prop"; let { [named]: computed } = { prop: "b" }; void computed; + +const notPresent = "prop2"; + +let { [notPresent]: computed2 } = { prop: "b" }; //// [destructuredLateBoundNameHasCorrectTypes.js] @@ -14,3 +18,5 @@ void destructured; const named = "prop"; let { [named]: computed } = { prop: "b" }; void computed; +const notPresent = "prop2"; +let { [notPresent]: computed2 } = { prop: "b" }; diff --git a/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.symbols b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.symbols index 876cd9faeefa1..dbf0aac121dc0 100644 --- a/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.symbols +++ b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.symbols @@ -19,3 +19,11 @@ let { [named]: computed } = { prop: "b" }; void computed; >computed : Symbol(computed, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 5, 5)) +const notPresent = "prop2"; +>notPresent : Symbol(notPresent, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 8, 5)) + +let { [notPresent]: computed2 } = { prop: "b" }; +>notPresent : Symbol(notPresent, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 8, 5)) +>computed2 : Symbol(computed2, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 10, 5)) +>prop : Symbol(prop, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 10, 35)) + diff --git a/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.types b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.types index db8e19a598630..8d24b45e0ec0f 100644 --- a/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.types +++ b/tests/baselines/reference/destructuredLateBoundNameHasCorrectTypes.types @@ -25,3 +25,14 @@ void computed; >void computed : undefined >computed : string +const notPresent = "prop2"; +>notPresent : "prop2" +>"prop2" : "prop2" + +let { [notPresent]: computed2 } = { prop: "b" }; +>notPresent : "prop2" +>computed2 : any +>{ prop: "b" } : { prop: string; } +>prop : string +>"b" : "b" + diff --git a/tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts b/tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts index e112ec453b06e..b2e6538e49e52 100644 --- a/tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts +++ b/tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts @@ -6,3 +6,7 @@ const named = "prop"; let { [named]: computed } = { prop: "b" }; void computed; + +const notPresent = "prop2"; + +let { [notPresent]: computed2 } = { prop: "b" };