Skip to content

Commit 34aed6e

Browse files
committed
support nested bindings
1 parent c914ebf commit 34aed6e

6 files changed

+323
-2
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27162,7 +27162,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2716227162
return isConstantReference((node as AccessExpression).expression) && isReadonlySymbol(getNodeLinks(node).resolvedSymbol || unknownSymbol);
2716327163
case SyntaxKind.ObjectBindingPattern:
2716427164
case SyntaxKind.ArrayBindingPattern:
27165-
return isVariableDeclaration(node.parent) && isVarConstLike(node.parent);
27165+
return isBindingElement(node.parent) ? isConstantReference(node.parent.parent) : isVariableDeclaration(node.parent) && isVarConstLike(node.parent);
2716627166
}
2716727167
return false;
2716827168
}

tests/baselines/reference/controlFlowAliasedDiscriminants.errors.txt

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ controlFlowAliasedDiscriminants.ts(39,9): error TS18048: 'data1' is possibly 'un
22
controlFlowAliasedDiscriminants.ts(40,9): error TS18048: 'data2' is possibly 'undefined'.
33
controlFlowAliasedDiscriminants.ts(65,9): error TS18048: 'bar2' is possibly 'undefined'.
44
controlFlowAliasedDiscriminants.ts(66,9): error TS18048: 'bar3' is possibly 'undefined'.
5+
controlFlowAliasedDiscriminants.ts(86,14): error TS1360: Type 'string | number' does not satisfy the expected type 'string'.
6+
Type 'number' is not assignable to type 'string'.
7+
controlFlowAliasedDiscriminants.ts(98,19): error TS1360: Type 'string | number' does not satisfy the expected type 'string'.
8+
Type 'number' is not assignable to type 'string'.
59

610

7-
==== controlFlowAliasedDiscriminants.ts (4 errors) ====
11+
==== controlFlowAliasedDiscriminants.ts (6 errors) ====
812
type UseQueryResult<T> = {
913
isSuccess: false;
1014
data: undefined;
@@ -81,4 +85,45 @@ controlFlowAliasedDiscriminants.ts(66,9): error TS18048: 'bar3' is possibly 'und
8185
!!! error TS18048: 'bar3' is possibly 'undefined'.
8286
}
8387
}
88+
89+
type Nested = {
90+
type: 'string';
91+
resp: {
92+
data: string
93+
}
94+
} | {
95+
type: 'number';
96+
resp: {
97+
data: number;
98+
}
99+
}
100+
101+
{
102+
let resp!: Nested;
103+
const { resp: { data }, type } = resp;
104+
if (type === 'string') {
105+
data satisfies string;
106+
~~~~~~~~~
107+
!!! error TS1360: Type 'string | number' does not satisfy the expected type 'string'.
108+
!!! error TS1360: Type 'number' is not assignable to type 'string'.
109+
}
110+
if (resp.type === 'string') {
111+
resp.resp.data satisfies string;
112+
}
113+
}
114+
115+
{
116+
117+
let resp!: Nested;
118+
const { resp: { data: dataAlias }, type } = resp;
119+
if (type === 'string') {
120+
dataAlias satisfies string;
121+
~~~~~~~~~
122+
!!! error TS1360: Type 'string | number' does not satisfy the expected type 'string'.
123+
!!! error TS1360: Type 'number' is not assignable to type 'string'.
124+
}
125+
if (resp.type === 'string') {
126+
resp.resp.data satisfies string;
127+
}
128+
}
84129

tests/baselines/reference/controlFlowAliasedDiscriminants.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,41 @@ declare function getArrayResult(): [true, number] | [false, undefined];
6969
bar3.toExponential(); // should error
7070
}
7171
}
72+
73+
type Nested = {
74+
type: 'string';
75+
resp: {
76+
data: string
77+
}
78+
} | {
79+
type: 'number';
80+
resp: {
81+
data: number;
82+
}
83+
}
84+
85+
{
86+
let resp!: Nested;
87+
const { resp: { data }, type } = resp;
88+
if (type === 'string') {
89+
data satisfies string;
90+
}
91+
if (resp.type === 'string') {
92+
resp.resp.data satisfies string;
93+
}
94+
}
95+
96+
{
97+
98+
let resp!: Nested;
99+
const { resp: { data: dataAlias }, type } = resp;
100+
if (type === 'string') {
101+
dataAlias satisfies string;
102+
}
103+
if (resp.type === 'string') {
104+
resp.resp.data satisfies string;
105+
}
106+
}
72107

73108

74109
//// [controlFlowAliasedDiscriminants.js]
@@ -125,3 +160,23 @@ if (areSuccess) {
125160
bar3.toExponential(); // should error
126161
}
127162
}
163+
{
164+
var resp = void 0;
165+
var data = resp.resp.data, type = resp.type;
166+
if (type === 'string') {
167+
data;
168+
}
169+
if (resp.type === 'string') {
170+
resp.resp.data;
171+
}
172+
}
173+
{
174+
var resp = void 0;
175+
var dataAlias = resp.resp.data, type = resp.type;
176+
if (type === 'string') {
177+
dataAlias;
178+
}
179+
if (resp.type === 'string') {
180+
resp.resp.data;
181+
}
182+
}

tests/baselines/reference/controlFlowAliasedDiscriminants.symbols

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,91 @@ declare function getArrayResult(): [true, number] | [false, undefined];
237237
}
238238
}
239239

240+
type Nested = {
241+
>Nested : Symbol(Nested, Decl(controlFlowAliasedDiscriminants.ts, 67, 1))
242+
243+
type: 'string';
244+
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 69, 15))
245+
246+
resp: {
247+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19))
248+
249+
data: string
250+
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 71, 11))
251+
}
252+
} | {
253+
type: 'number';
254+
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 74, 5))
255+
256+
resp: {
257+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 75, 19))
258+
259+
data: number;
260+
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 76, 11))
261+
}
262+
}
263+
264+
{
265+
let resp!: Nested;
266+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 82, 7))
267+
>Nested : Symbol(Nested, Decl(controlFlowAliasedDiscriminants.ts, 67, 1))
268+
269+
const { resp: { data }, type } = resp;
270+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19), Decl(controlFlowAliasedDiscriminants.ts, 75, 19))
271+
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 83, 19))
272+
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 83, 27))
273+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 82, 7))
274+
275+
if (type === 'string') {
276+
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 83, 27))
277+
278+
data satisfies string;
279+
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 83, 19))
280+
}
281+
if (resp.type === 'string') {
282+
>resp.type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 69, 15), Decl(controlFlowAliasedDiscriminants.ts, 74, 5))
283+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 82, 7))
284+
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 69, 15), Decl(controlFlowAliasedDiscriminants.ts, 74, 5))
285+
286+
resp.resp.data satisfies string;
287+
>resp.resp.data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 71, 11))
288+
>resp.resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19))
289+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 82, 7))
290+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19))
291+
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 71, 11))
292+
}
293+
}
294+
295+
{
296+
297+
let resp!: Nested;
298+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 94, 7))
299+
>Nested : Symbol(Nested, Decl(controlFlowAliasedDiscriminants.ts, 67, 1))
300+
301+
const { resp: { data: dataAlias }, type } = resp;
302+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19), Decl(controlFlowAliasedDiscriminants.ts, 75, 19))
303+
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 71, 11), Decl(controlFlowAliasedDiscriminants.ts, 76, 11))
304+
>dataAlias : Symbol(dataAlias, Decl(controlFlowAliasedDiscriminants.ts, 95, 19))
305+
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 95, 38))
306+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 94, 7))
307+
308+
if (type === 'string') {
309+
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 95, 38))
310+
311+
dataAlias satisfies string;
312+
>dataAlias : Symbol(dataAlias, Decl(controlFlowAliasedDiscriminants.ts, 95, 19))
313+
}
314+
if (resp.type === 'string') {
315+
>resp.type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 69, 15), Decl(controlFlowAliasedDiscriminants.ts, 74, 5))
316+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 94, 7))
317+
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 69, 15), Decl(controlFlowAliasedDiscriminants.ts, 74, 5))
318+
319+
resp.resp.data satisfies string;
320+
>resp.resp.data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 71, 11))
321+
>resp.resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19))
322+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 94, 7))
323+
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19))
324+
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 71, 11))
325+
}
326+
}
327+

tests/baselines/reference/controlFlowAliasedDiscriminants.types

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,3 +278,101 @@ declare function getArrayResult(): [true, number] | [false, undefined];
278278
}
279279
}
280280

281+
type Nested = {
282+
>Nested : { type: 'string'; resp: { data: string;}; } | { type: 'number'; resp: { data: number;}; }
283+
284+
type: 'string';
285+
>type : "string"
286+
287+
resp: {
288+
>resp : { data: string; }
289+
290+
data: string
291+
>data : string
292+
}
293+
} | {
294+
type: 'number';
295+
>type : "number"
296+
297+
resp: {
298+
>resp : { data: number; }
299+
300+
data: number;
301+
>data : number
302+
}
303+
}
304+
305+
{
306+
let resp!: Nested;
307+
>resp : Nested
308+
309+
const { resp: { data }, type } = resp;
310+
>resp : any
311+
>data : string | number
312+
>type : "string" | "number"
313+
>resp : Nested
314+
315+
if (type === 'string') {
316+
>type === 'string' : boolean
317+
>type : "string" | "number"
318+
>'string' : "string"
319+
320+
data satisfies string;
321+
>data satisfies string : string | number
322+
>data : string | number
323+
}
324+
if (resp.type === 'string') {
325+
>resp.type === 'string' : boolean
326+
>resp.type : "string" | "number"
327+
>resp : Nested
328+
>type : "string" | "number"
329+
>'string' : "string"
330+
331+
resp.resp.data satisfies string;
332+
>resp.resp.data satisfies string : string
333+
>resp.resp.data : string
334+
>resp.resp : { data: string; }
335+
>resp : { type: "string"; resp: { data: string; }; }
336+
>resp : { data: string; }
337+
>data : string
338+
}
339+
}
340+
341+
{
342+
343+
let resp!: Nested;
344+
>resp : Nested
345+
346+
const { resp: { data: dataAlias }, type } = resp;
347+
>resp : any
348+
>data : any
349+
>dataAlias : string | number
350+
>type : "string" | "number"
351+
>resp : Nested
352+
353+
if (type === 'string') {
354+
>type === 'string' : boolean
355+
>type : "string" | "number"
356+
>'string' : "string"
357+
358+
dataAlias satisfies string;
359+
>dataAlias satisfies string : string | number
360+
>dataAlias : string | number
361+
}
362+
if (resp.type === 'string') {
363+
>resp.type === 'string' : boolean
364+
>resp.type : "string" | "number"
365+
>resp : Nested
366+
>type : "string" | "number"
367+
>'string' : "string"
368+
369+
resp.resp.data satisfies string;
370+
>resp.resp.data satisfies string : string
371+
>resp.resp.data : string
372+
>resp.resp : { data: string; }
373+
>resp : { type: "string"; resp: { data: string; }; }
374+
>resp : { data: string; }
375+
>data : string
376+
}
377+
}
378+

tests/cases/compiler/controlFlowAliasedDiscriminants.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,38 @@ declare function getArrayResult(): [true, number] | [false, undefined];
6969
bar3.toExponential(); // should error
7070
}
7171
}
72+
73+
type Nested = {
74+
type: 'string';
75+
resp: {
76+
data: string
77+
}
78+
} | {
79+
type: 'number';
80+
resp: {
81+
data: number;
82+
}
83+
}
84+
85+
{
86+
let resp!: Nested;
87+
const { resp: { data }, type } = resp;
88+
if (type === 'string') {
89+
data satisfies string;
90+
}
91+
if (resp.type === 'string') {
92+
resp.resp.data satisfies string;
93+
}
94+
}
95+
96+
{
97+
98+
let resp!: Nested;
99+
const { resp: { data: dataAlias }, type } = resp;
100+
if (type === 'string') {
101+
dataAlias satisfies string;
102+
}
103+
if (resp.type === 'string') {
104+
resp.resp.data satisfies string;
105+
}
106+
}

0 commit comments

Comments
 (0)