Skip to content

Commit 2d7c54b

Browse files
committed
Add Support for Using Aliased Discriminants in Conditional Statements
1 parent 8af8f3c commit 2d7c54b

6 files changed

+804
-0
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27160,6 +27160,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2716027160
case SyntaxKind.ElementAccessExpression:
2716127161
// The resolvedSymbol property is initialized by checkPropertyAccess or checkElementAccess before we get here.
2716227162
return isConstantReference((node as AccessExpression).expression) && isReadonlySymbol(getNodeLinks(node).resolvedSymbol || unknownSymbol);
27163+
case SyntaxKind.ObjectBindingPattern:
27164+
case SyntaxKind.ArrayBindingPattern:
27165+
return isVariableDeclaration(node.parent) && isVarConstLike(node.parent);
2716327166
}
2716427167
return false;
2716527168
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
controlFlowAliasedDiscriminants.ts(39,9): error TS18048: 'data1' is possibly 'undefined'.
2+
controlFlowAliasedDiscriminants.ts(40,9): error TS18048: 'data2' is possibly 'undefined'.
3+
controlFlowAliasedDiscriminants.ts(65,9): error TS18048: 'bar2' is possibly 'undefined'.
4+
controlFlowAliasedDiscriminants.ts(66,9): error TS18048: 'bar3' is possibly 'undefined'.
5+
6+
7+
==== controlFlowAliasedDiscriminants.ts (4 errors) ====
8+
type UseQueryResult<T> = {
9+
isSuccess: false;
10+
data: undefined;
11+
} | {
12+
isSuccess: true;
13+
data: T
14+
};
15+
16+
function useQuery(): UseQueryResult<number> {
17+
return {
18+
isSuccess: false,
19+
data: undefined,
20+
};
21+
}
22+
23+
const { data: data1, isSuccess: isSuccess1 } = useQuery();
24+
const { data: data2, isSuccess: isSuccess2 } = useQuery();
25+
const { data: data3, isSuccess: isSuccess3 } = useQuery();
26+
27+
if (isSuccess1 && isSuccess2 && isSuccess3) {
28+
data1.toExponential(); // should ok
29+
data2.toExponential(); // should ok
30+
data3.toExponential(); // should ok
31+
}
32+
33+
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
34+
if (areSuccess) {
35+
data1.toExponential(); // should ok
36+
data2.toExponential(); // should ok
37+
data3.toExponential(); // should ok
38+
}
39+
40+
{
41+
let { data: data1, isSuccess: isSuccess1 } = useQuery();
42+
let { data: data2, isSuccess: isSuccess2 } = useQuery();
43+
const { data: data3, isSuccess: isSuccess3 } = useQuery();
44+
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
45+
if (areSuccess) {
46+
data1.toExponential(); // should error
47+
~~~~~
48+
!!! error TS18048: 'data1' is possibly 'undefined'.
49+
data2.toExponential(); // should error
50+
~~~~~
51+
!!! error TS18048: 'data2' is possibly 'undefined'.
52+
data3.toExponential(); // should ok
53+
}
54+
}
55+
56+
declare function getArrayResult(): [true, number] | [false, undefined];
57+
{
58+
const [foo1, bar1] = getArrayResult();
59+
const [foo2, bar2] = getArrayResult();
60+
const [foo3, bar3] = getArrayResult();
61+
const arrayAllSuccess = foo1 && foo2 && foo3;
62+
if (arrayAllSuccess) {
63+
bar1.toExponential(); // should ok
64+
bar2.toExponential(); // should ok
65+
bar3.toExponential(); // should ok
66+
}
67+
}
68+
69+
{
70+
const [foo1, bar1] = getArrayResult();
71+
let [foo2, bar2] = getArrayResult();
72+
let [foo3, bar3] = getArrayResult();
73+
const arrayAllSuccess = foo1 && foo2 && foo3;
74+
if (arrayAllSuccess) {
75+
bar1.toExponential(); // should ok
76+
bar2.toExponential(); // should error
77+
~~~~
78+
!!! error TS18048: 'bar2' is possibly 'undefined'.
79+
bar3.toExponential(); // should error
80+
~~~~
81+
!!! error TS18048: 'bar3' is possibly 'undefined'.
82+
}
83+
}
84+
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
//// [tests/cases/compiler/controlFlowAliasedDiscriminants.ts] ////
2+
3+
//// [controlFlowAliasedDiscriminants.ts]
4+
type UseQueryResult<T> = {
5+
isSuccess: false;
6+
data: undefined;
7+
} | {
8+
isSuccess: true;
9+
data: T
10+
};
11+
12+
function useQuery(): UseQueryResult<number> {
13+
return {
14+
isSuccess: false,
15+
data: undefined,
16+
};
17+
}
18+
19+
const { data: data1, isSuccess: isSuccess1 } = useQuery();
20+
const { data: data2, isSuccess: isSuccess2 } = useQuery();
21+
const { data: data3, isSuccess: isSuccess3 } = useQuery();
22+
23+
if (isSuccess1 && isSuccess2 && isSuccess3) {
24+
data1.toExponential(); // should ok
25+
data2.toExponential(); // should ok
26+
data3.toExponential(); // should ok
27+
}
28+
29+
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
30+
if (areSuccess) {
31+
data1.toExponential(); // should ok
32+
data2.toExponential(); // should ok
33+
data3.toExponential(); // should ok
34+
}
35+
36+
{
37+
let { data: data1, isSuccess: isSuccess1 } = useQuery();
38+
let { data: data2, isSuccess: isSuccess2 } = useQuery();
39+
const { data: data3, isSuccess: isSuccess3 } = useQuery();
40+
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
41+
if (areSuccess) {
42+
data1.toExponential(); // should error
43+
data2.toExponential(); // should error
44+
data3.toExponential(); // should ok
45+
}
46+
}
47+
48+
declare function getArrayResult(): [true, number] | [false, undefined];
49+
{
50+
const [foo1, bar1] = getArrayResult();
51+
const [foo2, bar2] = getArrayResult();
52+
const [foo3, bar3] = getArrayResult();
53+
const arrayAllSuccess = foo1 && foo2 && foo3;
54+
if (arrayAllSuccess) {
55+
bar1.toExponential(); // should ok
56+
bar2.toExponential(); // should ok
57+
bar3.toExponential(); // should ok
58+
}
59+
}
60+
61+
{
62+
const [foo1, bar1] = getArrayResult();
63+
let [foo2, bar2] = getArrayResult();
64+
let [foo3, bar3] = getArrayResult();
65+
const arrayAllSuccess = foo1 && foo2 && foo3;
66+
if (arrayAllSuccess) {
67+
bar1.toExponential(); // should ok
68+
bar2.toExponential(); // should error
69+
bar3.toExponential(); // should error
70+
}
71+
}
72+
73+
74+
//// [controlFlowAliasedDiscriminants.js]
75+
function useQuery() {
76+
return {
77+
isSuccess: false,
78+
data: undefined,
79+
};
80+
}
81+
var _a = useQuery(), data1 = _a.data, isSuccess1 = _a.isSuccess;
82+
var _b = useQuery(), data2 = _b.data, isSuccess2 = _b.isSuccess;
83+
var _c = useQuery(), data3 = _c.data, isSuccess3 = _c.isSuccess;
84+
if (isSuccess1 && isSuccess2 && isSuccess3) {
85+
data1.toExponential(); // should ok
86+
data2.toExponential(); // should ok
87+
data3.toExponential(); // should ok
88+
}
89+
var areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
90+
if (areSuccess) {
91+
data1.toExponential(); // should ok
92+
data2.toExponential(); // should ok
93+
data3.toExponential(); // should ok
94+
}
95+
{
96+
var _d = useQuery(), data1_1 = _d.data, isSuccess1_1 = _d.isSuccess;
97+
var _e = useQuery(), data2_1 = _e.data, isSuccess2_1 = _e.isSuccess;
98+
var _f = useQuery(), data3_1 = _f.data, isSuccess3_1 = _f.isSuccess;
99+
var areSuccess_1 = isSuccess1_1 && isSuccess2_1 && isSuccess3_1;
100+
if (areSuccess_1) {
101+
data1_1.toExponential(); // should error
102+
data2_1.toExponential(); // should error
103+
data3_1.toExponential(); // should ok
104+
}
105+
}
106+
{
107+
var _g = getArrayResult(), foo1 = _g[0], bar1 = _g[1];
108+
var _h = getArrayResult(), foo2 = _h[0], bar2 = _h[1];
109+
var _j = getArrayResult(), foo3 = _j[0], bar3 = _j[1];
110+
var arrayAllSuccess = foo1 && foo2 && foo3;
111+
if (arrayAllSuccess) {
112+
bar1.toExponential(); // should ok
113+
bar2.toExponential(); // should ok
114+
bar3.toExponential(); // should ok
115+
}
116+
}
117+
{
118+
var _k = getArrayResult(), foo1 = _k[0], bar1 = _k[1];
119+
var _l = getArrayResult(), foo2 = _l[0], bar2 = _l[1];
120+
var _m = getArrayResult(), foo3 = _m[0], bar3 = _m[1];
121+
var arrayAllSuccess = foo1 && foo2 && foo3;
122+
if (arrayAllSuccess) {
123+
bar1.toExponential(); // should ok
124+
bar2.toExponential(); // should error
125+
bar3.toExponential(); // should error
126+
}
127+
}

0 commit comments

Comments
 (0)