Skip to content

Commit b2e0c4b

Browse files
authored
Add support for destructuring well-known and late-bound names (#23297)
* Add support for destructuring well-known and late-bound names * Add test of not present late bound prop
1 parent 1243d1a commit b2e0c4b

6 files changed

+125
-3
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4174,14 +4174,17 @@ namespace ts {
41744174
else {
41754175
// Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
41764176
const name = declaration.propertyName || <Identifier>declaration.name;
4177-
if (isComputedNonLiteralName(name)) {
4178-
// computed properties with non-literal names are treated as 'any'
4177+
const isLate = isLateBindableName(name);
4178+
const isWellKnown = isComputedPropertyName(name) && isWellKnownSymbolSyntactically(name.expression);
4179+
if (!isLate && !isWellKnown && isComputedNonLiteralName(name)) {
41794180
return anyType;
41804181
}
41814182

41824183
// Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature,
41834184
// or otherwise the type of the string index signature.
4184-
const text = getTextOfPropertyName(name);
4185+
const text = isLate ? getLateBoundNameFromType(checkComputedPropertyName(name as ComputedPropertyName) as LiteralType | UniqueESSymbolType) :
4186+
isWellKnown ? getPropertyNameForKnownSymbolName(idText(((name as ComputedPropertyName).expression as PropertyAccessExpression).name)) :
4187+
getTextOfPropertyName(name);
41854188

41864189
// Relax null check on ambient destructuring parameters, since the parameters have no implementation and are just documentation
41874190
if (strictNullChecks && declaration.flags & NodeFlags.Ambient && isParameterDeclaration(declaration)) {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts(11,7): error TS2459: Type '{ prop: string; }' has no property '[notPresent]' and no string index signature.
2+
3+
4+
==== tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts (1 errors) ====
5+
let { [Symbol.iterator]: destructured } = [];
6+
void destructured;
7+
8+
const named = "prop";
9+
10+
let { [named]: computed } = { prop: "b" };
11+
void computed;
12+
13+
const notPresent = "prop2";
14+
15+
let { [notPresent]: computed2 } = { prop: "b" };
16+
~~~~~~~~~~~~
17+
!!! error TS2459: Type '{ prop: string; }' has no property '[notPresent]' and no string index signature.
18+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [destructuredLateBoundNameHasCorrectTypes.ts]
2+
let { [Symbol.iterator]: destructured } = [];
3+
void destructured;
4+
5+
const named = "prop";
6+
7+
let { [named]: computed } = { prop: "b" };
8+
void computed;
9+
10+
const notPresent = "prop2";
11+
12+
let { [notPresent]: computed2 } = { prop: "b" };
13+
14+
15+
//// [destructuredLateBoundNameHasCorrectTypes.js]
16+
let { [Symbol.iterator]: destructured } = [];
17+
void destructured;
18+
const named = "prop";
19+
let { [named]: computed } = { prop: "b" };
20+
void computed;
21+
const notPresent = "prop2";
22+
let { [notPresent]: computed2 } = { prop: "b" };
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
=== tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts ===
2+
let { [Symbol.iterator]: destructured } = [];
3+
>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
4+
>Symbol : Symbol(Symbol, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --))
5+
>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
6+
>destructured : Symbol(destructured, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 0, 5))
7+
8+
void destructured;
9+
>destructured : Symbol(destructured, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 0, 5))
10+
11+
const named = "prop";
12+
>named : Symbol(named, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 3, 5))
13+
14+
let { [named]: computed } = { prop: "b" };
15+
>named : Symbol(named, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 3, 5))
16+
>computed : Symbol(computed, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 5, 5))
17+
>prop : Symbol(prop, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 5, 29))
18+
19+
void computed;
20+
>computed : Symbol(computed, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 5, 5))
21+
22+
const notPresent = "prop2";
23+
>notPresent : Symbol(notPresent, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 8, 5))
24+
25+
let { [notPresent]: computed2 } = { prop: "b" };
26+
>notPresent : Symbol(notPresent, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 8, 5))
27+
>computed2 : Symbol(computed2, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 10, 5))
28+
>prop : Symbol(prop, Decl(destructuredLateBoundNameHasCorrectTypes.ts, 10, 35))
29+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
=== tests/cases/compiler/destructuredLateBoundNameHasCorrectTypes.ts ===
2+
let { [Symbol.iterator]: destructured } = [];
3+
>Symbol.iterator : symbol
4+
>Symbol : SymbolConstructor
5+
>iterator : symbol
6+
>destructured : () => IterableIterator<undefined>
7+
>[] : undefined[]
8+
9+
void destructured;
10+
>void destructured : undefined
11+
>destructured : () => IterableIterator<undefined>
12+
13+
const named = "prop";
14+
>named : "prop"
15+
>"prop" : "prop"
16+
17+
let { [named]: computed } = { prop: "b" };
18+
>named : "prop"
19+
>computed : string
20+
>{ prop: "b" } : { prop: string; }
21+
>prop : string
22+
>"b" : "b"
23+
24+
void computed;
25+
>void computed : undefined
26+
>computed : string
27+
28+
const notPresent = "prop2";
29+
>notPresent : "prop2"
30+
>"prop2" : "prop2"
31+
32+
let { [notPresent]: computed2 } = { prop: "b" };
33+
>notPresent : "prop2"
34+
>computed2 : any
35+
>{ prop: "b" } : { prop: string; }
36+
>prop : string
37+
>"b" : "b"
38+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// @target: es6
2+
let { [Symbol.iterator]: destructured } = [];
3+
void destructured;
4+
5+
const named = "prop";
6+
7+
let { [named]: computed } = { prop: "b" };
8+
void computed;
9+
10+
const notPresent = "prop2";
11+
12+
let { [notPresent]: computed2 } = { prop: "b" };

0 commit comments

Comments
 (0)