Skip to content

Commit 746bdb7

Browse files
committed
Fix getContextualTypeForBindingElement for arrays
When handling an array type, the lookup should use the position index instead of the identifier name. Also uncomment the tests in the `staticFieldWithInterfaceContext.ts` test which failed because of this bug. Fixes microsoft#40158.
1 parent 7e86b3e commit 746bdb7

10 files changed

+262
-37
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23023,12 +23023,16 @@ namespace ts {
2302323023
const name = declaration.propertyName || declaration.name;
2302423024
const parentType = getContextualTypeForVariableLikeDeclaration(parent) ||
2302523025
parent.kind !== SyntaxKind.BindingElement && parent.initializer && checkDeclarationInitializer(parent);
23026-
if (parentType && !isBindingPattern(name) && !isComputedNonLiteralName(name)) {
23027-
const nameType = getLiteralTypeFromPropertyName(name);
23028-
if (isTypeUsableAsPropertyName(nameType)) {
23029-
const text = getPropertyNameFromType(nameType);
23030-
return getTypeOfPropertyOfType(parentType, text);
23031-
}
23026+
if (!parentType || isBindingPattern(name) || isComputedNonLiteralName(name)) return undefined;
23027+
if (parent.name.kind === SyntaxKind.ArrayBindingPattern) {
23028+
const index = indexOfNode(declaration.parent.elements, declaration);
23029+
if (index < 0) return undefined;
23030+
return getContextualTypeForElementExpression(parentType, index);
23031+
}
23032+
const nameType = getLiteralTypeFromPropertyName(name);
23033+
if (isTypeUsableAsPropertyName(nameType)) {
23034+
const text = getPropertyNameFromType(nameType);
23035+
return getTypeOfPropertyOfType(parentType, text);
2303223036
}
2303323037
}
2303423038

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tests/cases/compiler/contextualTypingArrayDestructuringWithDefaults.ts(8,10): error TS2322: Type '{ a: number; }' is not assignable to type '1'.
2+
3+
4+
==== tests/cases/compiler/contextualTypingArrayDestructuringWithDefaults.ts (1 errors) ====
5+
type I = { a: "a" };
6+
let [ c0 = {a: "a"} ]: [I?] = [];
7+
let [ x1, c1 = {a: "a"} ]: [number, I?] = [1];
8+
let [ c_ = {a: "a"} ]: I[] = [];
9+
10+
// not a great example, expect an error
11+
function foo() {
12+
let {length = {a: 1}}: [number] = [1];
13+
~~~~~~
14+
!!! error TS2322: Type '{ a: number; }' is not assignable to type '1'.
15+
return length;
16+
}
17+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [contextualTypingArrayDestructuringWithDefaults.ts]
2+
type I = { a: "a" };
3+
let [ c0 = {a: "a"} ]: [I?] = [];
4+
let [ x1, c1 = {a: "a"} ]: [number, I?] = [1];
5+
let [ c_ = {a: "a"} ]: I[] = [];
6+
7+
// not a great example, expect an error
8+
function foo() {
9+
let {length = {a: 1}}: [number] = [1];
10+
return length;
11+
}
12+
13+
14+
//// [contextualTypingArrayDestructuringWithDefaults.js]
15+
var _a = [][0], c0 = _a === void 0 ? { a: "a" } : _a;
16+
var _b = [1], x1 = _b[0], _c = _b[1], c1 = _c === void 0 ? { a: "a" } : _c;
17+
var _d = [][0], c_ = _d === void 0 ? { a: "a" } : _d;
18+
// not a great example, expect an error
19+
function foo() {
20+
var _a = [1].length, length = _a === void 0 ? { a: 1 } : _a;
21+
return length;
22+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/compiler/contextualTypingArrayDestructuringWithDefaults.ts ===
2+
type I = { a: "a" };
3+
>I : Symbol(I, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 0, 0))
4+
>a : Symbol(a, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 0, 10))
5+
6+
let [ c0 = {a: "a"} ]: [I?] = [];
7+
>c0 : Symbol(c0, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 1, 5))
8+
>a : Symbol(a, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 1, 12))
9+
>I : Symbol(I, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 0, 0))
10+
11+
let [ x1, c1 = {a: "a"} ]: [number, I?] = [1];
12+
>x1 : Symbol(x1, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 2, 5))
13+
>c1 : Symbol(c1, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 2, 9))
14+
>a : Symbol(a, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 2, 16))
15+
>I : Symbol(I, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 0, 0))
16+
17+
let [ c_ = {a: "a"} ]: I[] = [];
18+
>c_ : Symbol(c_, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 3, 5))
19+
>a : Symbol(a, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 3, 12))
20+
>I : Symbol(I, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 0, 0))
21+
22+
// not a great example, expect an error
23+
function foo() {
24+
>foo : Symbol(foo, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 3, 32))
25+
26+
let {length = {a: 1}}: [number] = [1];
27+
>length : Symbol(length, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 7, 9))
28+
>a : Symbol(a, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 7, 19))
29+
30+
return length;
31+
>length : Symbol(length, Decl(contextualTypingArrayDestructuringWithDefaults.ts, 7, 9))
32+
}
33+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
=== tests/cases/compiler/contextualTypingArrayDestructuringWithDefaults.ts ===
2+
type I = { a: "a" };
3+
>I : I
4+
>a : "a"
5+
6+
let [ c0 = {a: "a"} ]: [I?] = [];
7+
>c0 : I
8+
>{a: "a"} : { a: "a"; }
9+
>a : "a"
10+
>"a" : "a"
11+
>[] : []
12+
13+
let [ x1, c1 = {a: "a"} ]: [number, I?] = [1];
14+
>x1 : number
15+
>c1 : I
16+
>{a: "a"} : { a: "a"; }
17+
>a : "a"
18+
>"a" : "a"
19+
>[1] : [number]
20+
>1 : 1
21+
22+
let [ c_ = {a: "a"} ]: I[] = [];
23+
>c_ : I
24+
>{a: "a"} : { a: "a"; }
25+
>a : "a"
26+
>"a" : "a"
27+
>[] : undefined[]
28+
29+
// not a great example, expect an error
30+
function foo() {
31+
>foo : () => 1
32+
33+
let {length = {a: 1}}: [number] = [1];
34+
>length : 1
35+
>{a: 1} : { a: number; }
36+
>a : number
37+
>1 : 1
38+
>[1] : [number]
39+
>1 : 1
40+
41+
return length;
42+
>length : 1
43+
}
44+

tests/baselines/reference/staticFieldWithInterfaceContext.js

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,14 @@ let { c: c5 = class { static x = { a: "a" } }}: { c?: I } = { c: class { static
2020
let [ c6 ]: [I] = [class { static x = { a: "a" } }];
2121
let [ c7 ]: I[] = [class { static x = { a: "a" } }];
2222

23-
// These are broken because of #40158
24-
// let [ c8 = class { static x = { a: "a" } } ]: [I?] = [];
25-
// let [ c9 = class { static x = { a: "a" } } ]: I[] = [];
26-
// let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }];
27-
// let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }];
23+
let [ c8 = class { static x = { a: "a" } } ]: [I?] = [];
24+
let [ c9 = class { static x = { a: "a" } } ]: I[] = [];
25+
let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }];
26+
let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }];
2827

2928

3029
//// [staticFieldWithInterfaceContext.js]
31-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
30+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
3231
var c = (_a = /** @class */ (function () {
3332
function class_1() {
3433
}
@@ -65,26 +64,26 @@ var c3 = { c: (_d = /** @class */ (function () {
6564
}()),
6665
_d.x = { a: "a" },
6766
_d) }.c;
68-
var _k = {}.c, c4 = _k === void 0 ? (_e = /** @class */ (function () {
67+
var _r = {}.c, c4 = _r === void 0 ? (_e = /** @class */ (function () {
6968
function class_5() {
7069
}
7170
return class_5;
7271
}()),
7372
_e.x = { a: "a" },
74-
_e) : _k;
75-
var _l = { c: (_g = /** @class */ (function () {
73+
_e) : _r;
74+
var _s = { c: (_g = /** @class */ (function () {
7675
function class_6() {
7776
}
7877
return class_6;
7978
}()),
8079
_g.x = { a: "a" },
81-
_g) }.c, c5 = _l === void 0 ? (_f = /** @class */ (function () {
80+
_g) }.c, c5 = _s === void 0 ? (_f = /** @class */ (function () {
8281
function class_7() {
8382
}
8483
return class_7;
8584
}()),
8685
_f.x = { a: "a" },
87-
_f) : _l;
86+
_f) : _s;
8887
var c6 = [(_h = /** @class */ (function () {
8988
function class_8() {
9089
}
@@ -99,8 +98,43 @@ var c7 = [(_j = /** @class */ (function () {
9998
}()),
10099
_j.x = { a: "a" },
101100
_j)][0];
102-
// These are broken because of #40158
103-
// let [ c8 = class { static x = { a: "a" } } ]: [I?] = [];
104-
// let [ c9 = class { static x = { a: "a" } } ]: I[] = [];
105-
// let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }];
106-
// let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }];
101+
var _t = [][0], c8 = _t === void 0 ? (_k = /** @class */ (function () {
102+
function class_10() {
103+
}
104+
return class_10;
105+
}()),
106+
_k.x = { a: "a" },
107+
_k) : _t;
108+
var _u = [][0], c9 = _u === void 0 ? (_l = /** @class */ (function () {
109+
function class_11() {
110+
}
111+
return class_11;
112+
}()),
113+
_l.x = { a: "a" },
114+
_l) : _u;
115+
var _v = [(_o = /** @class */ (function () {
116+
function class_12() {
117+
}
118+
return class_12;
119+
}()),
120+
_o.x = { a: "a" },
121+
_o)][0], c10 = _v === void 0 ? (_m = /** @class */ (function () {
122+
function class_13() {
123+
}
124+
return class_13;
125+
}()),
126+
_m.x = { a: "a" },
127+
_m) : _v;
128+
var _w = [(_q = /** @class */ (function () {
129+
function class_14() {
130+
}
131+
return class_14;
132+
}()),
133+
_q.x = { a: "a" },
134+
_q)][0], c11 = _w === void 0 ? (_p = /** @class */ (function () {
135+
function class_15() {
136+
}
137+
return class_15;
138+
}()),
139+
_p.x = { a: "a" },
140+
_p) : _w;

tests/baselines/reference/staticFieldWithInterfaceContext.symbols

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,31 @@ let [ c7 ]: I[] = [class { static x = { a: "a" } }];
8484
>x : Symbol((Anonymous class).x, Decl(staticFieldWithInterfaceContext.ts, 19, 26))
8585
>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 19, 39))
8686

87-
// These are broken because of #40158
88-
// let [ c8 = class { static x = { a: "a" } } ]: [I?] = [];
89-
// let [ c9 = class { static x = { a: "a" } } ]: I[] = [];
90-
// let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }];
91-
// let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }];
87+
let [ c8 = class { static x = { a: "a" } } ]: [I?] = [];
88+
>c8 : Symbol(c8, Decl(staticFieldWithInterfaceContext.ts, 21, 5))
89+
>x : Symbol(c8.x, Decl(staticFieldWithInterfaceContext.ts, 21, 18))
90+
>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 21, 31))
91+
>I : Symbol(I, Decl(staticFieldWithInterfaceContext.ts, 0, 0))
92+
93+
let [ c9 = class { static x = { a: "a" } } ]: I[] = [];
94+
>c9 : Symbol(c9, Decl(staticFieldWithInterfaceContext.ts, 22, 5))
95+
>x : Symbol(c9.x, Decl(staticFieldWithInterfaceContext.ts, 22, 18))
96+
>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 22, 31))
97+
>I : Symbol(I, Decl(staticFieldWithInterfaceContext.ts, 0, 0))
98+
99+
let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }];
100+
>c10 : Symbol(c10, Decl(staticFieldWithInterfaceContext.ts, 23, 5))
101+
>x : Symbol(c10.x, Decl(staticFieldWithInterfaceContext.ts, 23, 19))
102+
>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 23, 32))
103+
>I : Symbol(I, Decl(staticFieldWithInterfaceContext.ts, 0, 0))
104+
>x : Symbol((Anonymous class).x, Decl(staticFieldWithInterfaceContext.ts, 23, 62))
105+
>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 23, 75))
106+
107+
let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }];
108+
>c11 : Symbol(c11, Decl(staticFieldWithInterfaceContext.ts, 24, 5))
109+
>x : Symbol(c11.x, Decl(staticFieldWithInterfaceContext.ts, 24, 19))
110+
>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 24, 32))
111+
>I : Symbol(I, Decl(staticFieldWithInterfaceContext.ts, 0, 0))
112+
>x : Symbol((Anonymous class).x, Decl(staticFieldWithInterfaceContext.ts, 24, 61))
113+
>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 24, 74))
92114

tests/baselines/reference/staticFieldWithInterfaceContext.types

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,49 @@ let [ c7 ]: I[] = [class { static x = { a: "a" } }];
114114
>a : "a"
115115
>"a" : "a"
116116

117-
// These are broken because of #40158
118-
// let [ c8 = class { static x = { a: "a" } } ]: [I?] = [];
119-
// let [ c9 = class { static x = { a: "a" } } ]: I[] = [];
120-
// let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }];
121-
// let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }];
117+
let [ c8 = class { static x = { a: "a" } } ]: [I?] = [];
118+
>c8 : I
119+
>class { static x = { a: "a" } } : typeof c8
120+
>x : { a: "a"; }
121+
>{ a: "a" } : { a: "a"; }
122+
>a : "a"
123+
>"a" : "a"
124+
>[] : []
125+
126+
let [ c9 = class { static x = { a: "a" } } ]: I[] = [];
127+
>c9 : I
128+
>class { static x = { a: "a" } } : typeof c9
129+
>x : { a: "a"; }
130+
>{ a: "a" } : { a: "a"; }
131+
>a : "a"
132+
>"a" : "a"
133+
>[] : undefined[]
134+
135+
let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }];
136+
>c10 : I
137+
>class { static x = { a: "a" } } : typeof c10
138+
>x : { a: "a"; }
139+
>{ a: "a" } : { a: "a"; }
140+
>a : "a"
141+
>"a" : "a"
142+
>[class { static x = { a: "a" } }] : [typeof (Anonymous class)]
143+
>class { static x = { a: "a" } } : typeof (Anonymous class)
144+
>x : { a: "a"; }
145+
>{ a: "a" } : { a: "a"; }
146+
>a : "a"
147+
>"a" : "a"
148+
149+
let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }];
150+
>c11 : I
151+
>class { static x = { a: "a" } } : typeof c11
152+
>x : { a: "a"; }
153+
>{ a: "a" } : { a: "a"; }
154+
>a : "a"
155+
>"a" : "a"
156+
>[class { static x = { a: "a" } }] : (typeof (Anonymous class))[]
157+
>class { static x = { a: "a" } } : typeof (Anonymous class)
158+
>x : { a: "a"; }
159+
>{ a: "a" } : { a: "a"; }
160+
>a : "a"
161+
>"a" : "a"
122162

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
type I = { a: "a" };
2+
let [ c0 = {a: "a"} ]: [I?] = [];
3+
let [ x1, c1 = {a: "a"} ]: [number, I?] = [1];
4+
let [ c_ = {a: "a"} ]: I[] = [];
5+
6+
// not a great example, expect an error
7+
function foo() {
8+
let {length = {a: 1}}: [number] = [1];
9+
return length;
10+
}

tests/cases/compiler/staticFieldWithInterfaceContext.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ let { c: c5 = class { static x = { a: "a" } }}: { c?: I } = { c: class { static
1919
let [ c6 ]: [I] = [class { static x = { a: "a" } }];
2020
let [ c7 ]: I[] = [class { static x = { a: "a" } }];
2121

22-
// These are broken because of #40158
23-
// let [ c8 = class { static x = { a: "a" } } ]: [I?] = [];
24-
// let [ c9 = class { static x = { a: "a" } } ]: I[] = [];
25-
// let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }];
26-
// let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }];
22+
let [ c8 = class { static x = { a: "a" } } ]: [I?] = [];
23+
let [ c9 = class { static x = { a: "a" } } ]: I[] = [];
24+
let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }];
25+
let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }];

0 commit comments

Comments
 (0)