Add Support for Using Aliased Discriminants in Conditional Statements (#56173)

This commit is contained in:
Zzzen 2023-11-09 07:06:40 +08:00 committed by GitHub
parent 50f48840a3
commit 7b96c28e8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1126 additions and 0 deletions

View File

@ -27244,6 +27244,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
case SyntaxKind.ElementAccessExpression:
// The resolvedSymbol property is initialized by checkPropertyAccess or checkElementAccess before we get here.
return isConstantReference((node as AccessExpression).expression) && isReadonlySymbol(getNodeLinks(node).resolvedSymbol || unknownSymbol);
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
const rootDeclaration = getRootDeclaration(node.parent);
return isVariableDeclaration(rootDeclaration) && isVarConstLike(rootDeclaration);
}
return false;
}

View File

@ -0,0 +1,129 @@
controlFlowAliasedDiscriminants.ts(39,9): error TS18048: 'data1' is possibly 'undefined'.
controlFlowAliasedDiscriminants.ts(40,9): error TS18048: 'data2' is possibly 'undefined'.
controlFlowAliasedDiscriminants.ts(65,9): error TS18048: 'bar2' is possibly 'undefined'.
controlFlowAliasedDiscriminants.ts(66,9): error TS18048: 'bar3' is possibly 'undefined'.
controlFlowAliasedDiscriminants.ts(86,14): error TS1360: Type 'string | number' does not satisfy the expected type 'string'.
Type 'number' is not assignable to type 'string'.
controlFlowAliasedDiscriminants.ts(98,19): error TS1360: Type 'string | number' does not satisfy the expected type 'string'.
Type 'number' is not assignable to type 'string'.
==== controlFlowAliasedDiscriminants.ts (6 errors) ====
type UseQueryResult<T> = {
isSuccess: false;
data: undefined;
} | {
isSuccess: true;
data: T
};
function useQuery(): UseQueryResult<number> {
return {
isSuccess: false,
data: undefined,
};
}
const { data: data1, isSuccess: isSuccess1 } = useQuery();
const { data: data2, isSuccess: isSuccess2 } = useQuery();
const { data: data3, isSuccess: isSuccess3 } = useQuery();
if (isSuccess1 && isSuccess2 && isSuccess3) {
data1.toExponential(); // should ok
data2.toExponential(); // should ok
data3.toExponential(); // should ok
}
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
if (areSuccess) {
data1.toExponential(); // should ok
data2.toExponential(); // should ok
data3.toExponential(); // should ok
}
{
let { data: data1, isSuccess: isSuccess1 } = useQuery();
let { data: data2, isSuccess: isSuccess2 } = useQuery();
const { data: data3, isSuccess: isSuccess3 } = useQuery();
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
if (areSuccess) {
data1.toExponential(); // should error
~~~~~
!!! error TS18048: 'data1' is possibly 'undefined'.
data2.toExponential(); // should error
~~~~~
!!! error TS18048: 'data2' is possibly 'undefined'.
data3.toExponential(); // should ok
}
}
declare function getArrayResult(): [true, number] | [false, undefined];
{
const [foo1, bar1] = getArrayResult();
const [foo2, bar2] = getArrayResult();
const [foo3, bar3] = getArrayResult();
const arrayAllSuccess = foo1 && foo2 && foo3;
if (arrayAllSuccess) {
bar1.toExponential(); // should ok
bar2.toExponential(); // should ok
bar3.toExponential(); // should ok
}
}
{
const [foo1, bar1] = getArrayResult();
let [foo2, bar2] = getArrayResult();
let [foo3, bar3] = getArrayResult();
const arrayAllSuccess = foo1 && foo2 && foo3;
if (arrayAllSuccess) {
bar1.toExponential(); // should ok
bar2.toExponential(); // should error
~~~~
!!! error TS18048: 'bar2' is possibly 'undefined'.
bar3.toExponential(); // should error
~~~~
!!! error TS18048: 'bar3' is possibly 'undefined'.
}
}
type Nested = {
type: 'string';
resp: {
data: string
}
} | {
type: 'number';
resp: {
data: number;
}
}
{
let resp!: Nested;
const { resp: { data }, type } = resp;
if (type === 'string') {
data satisfies string;
~~~~~~~~~
!!! error TS1360: Type 'string | number' does not satisfy the expected type 'string'.
!!! error TS1360: Type 'number' is not assignable to type 'string'.
}
if (resp.type === 'string') {
resp.resp.data satisfies string;
}
}
{
let resp!: Nested;
const { resp: { data: dataAlias }, type } = resp;
if (type === 'string') {
dataAlias satisfies string;
~~~~~~~~~
!!! error TS1360: Type 'string | number' does not satisfy the expected type 'string'.
!!! error TS1360: Type 'number' is not assignable to type 'string'.
}
if (resp.type === 'string') {
resp.resp.data satisfies string;
}
}

View File

@ -0,0 +1,182 @@
//// [tests/cases/compiler/controlFlowAliasedDiscriminants.ts] ////
//// [controlFlowAliasedDiscriminants.ts]
type UseQueryResult<T> = {
isSuccess: false;
data: undefined;
} | {
isSuccess: true;
data: T
};
function useQuery(): UseQueryResult<number> {
return {
isSuccess: false,
data: undefined,
};
}
const { data: data1, isSuccess: isSuccess1 } = useQuery();
const { data: data2, isSuccess: isSuccess2 } = useQuery();
const { data: data3, isSuccess: isSuccess3 } = useQuery();
if (isSuccess1 && isSuccess2 && isSuccess3) {
data1.toExponential(); // should ok
data2.toExponential(); // should ok
data3.toExponential(); // should ok
}
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
if (areSuccess) {
data1.toExponential(); // should ok
data2.toExponential(); // should ok
data3.toExponential(); // should ok
}
{
let { data: data1, isSuccess: isSuccess1 } = useQuery();
let { data: data2, isSuccess: isSuccess2 } = useQuery();
const { data: data3, isSuccess: isSuccess3 } = useQuery();
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
if (areSuccess) {
data1.toExponential(); // should error
data2.toExponential(); // should error
data3.toExponential(); // should ok
}
}
declare function getArrayResult(): [true, number] | [false, undefined];
{
const [foo1, bar1] = getArrayResult();
const [foo2, bar2] = getArrayResult();
const [foo3, bar3] = getArrayResult();
const arrayAllSuccess = foo1 && foo2 && foo3;
if (arrayAllSuccess) {
bar1.toExponential(); // should ok
bar2.toExponential(); // should ok
bar3.toExponential(); // should ok
}
}
{
const [foo1, bar1] = getArrayResult();
let [foo2, bar2] = getArrayResult();
let [foo3, bar3] = getArrayResult();
const arrayAllSuccess = foo1 && foo2 && foo3;
if (arrayAllSuccess) {
bar1.toExponential(); // should ok
bar2.toExponential(); // should error
bar3.toExponential(); // should error
}
}
type Nested = {
type: 'string';
resp: {
data: string
}
} | {
type: 'number';
resp: {
data: number;
}
}
{
let resp!: Nested;
const { resp: { data }, type } = resp;
if (type === 'string') {
data satisfies string;
}
if (resp.type === 'string') {
resp.resp.data satisfies string;
}
}
{
let resp!: Nested;
const { resp: { data: dataAlias }, type } = resp;
if (type === 'string') {
dataAlias satisfies string;
}
if (resp.type === 'string') {
resp.resp.data satisfies string;
}
}
//// [controlFlowAliasedDiscriminants.js]
function useQuery() {
return {
isSuccess: false,
data: undefined,
};
}
var _a = useQuery(), data1 = _a.data, isSuccess1 = _a.isSuccess;
var _b = useQuery(), data2 = _b.data, isSuccess2 = _b.isSuccess;
var _c = useQuery(), data3 = _c.data, isSuccess3 = _c.isSuccess;
if (isSuccess1 && isSuccess2 && isSuccess3) {
data1.toExponential(); // should ok
data2.toExponential(); // should ok
data3.toExponential(); // should ok
}
var areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
if (areSuccess) {
data1.toExponential(); // should ok
data2.toExponential(); // should ok
data3.toExponential(); // should ok
}
{
var _d = useQuery(), data1_1 = _d.data, isSuccess1_1 = _d.isSuccess;
var _e = useQuery(), data2_1 = _e.data, isSuccess2_1 = _e.isSuccess;
var _f = useQuery(), data3_1 = _f.data, isSuccess3_1 = _f.isSuccess;
var areSuccess_1 = isSuccess1_1 && isSuccess2_1 && isSuccess3_1;
if (areSuccess_1) {
data1_1.toExponential(); // should error
data2_1.toExponential(); // should error
data3_1.toExponential(); // should ok
}
}
{
var _g = getArrayResult(), foo1 = _g[0], bar1 = _g[1];
var _h = getArrayResult(), foo2 = _h[0], bar2 = _h[1];
var _j = getArrayResult(), foo3 = _j[0], bar3 = _j[1];
var arrayAllSuccess = foo1 && foo2 && foo3;
if (arrayAllSuccess) {
bar1.toExponential(); // should ok
bar2.toExponential(); // should ok
bar3.toExponential(); // should ok
}
}
{
var _k = getArrayResult(), foo1 = _k[0], bar1 = _k[1];
var _l = getArrayResult(), foo2 = _l[0], bar2 = _l[1];
var _m = getArrayResult(), foo3 = _m[0], bar3 = _m[1];
var arrayAllSuccess = foo1 && foo2 && foo3;
if (arrayAllSuccess) {
bar1.toExponential(); // should ok
bar2.toExponential(); // should error
bar3.toExponential(); // should error
}
}
{
var resp = void 0;
var data = resp.resp.data, type = resp.type;
if (type === 'string') {
data;
}
if (resp.type === 'string') {
resp.resp.data;
}
}
{
var resp = void 0;
var dataAlias = resp.resp.data, type = resp.type;
if (type === 'string') {
dataAlias;
}
if (resp.type === 'string') {
resp.resp.data;
}
}

View File

@ -0,0 +1,327 @@
//// [tests/cases/compiler/controlFlowAliasedDiscriminants.ts] ////
=== controlFlowAliasedDiscriminants.ts ===
type UseQueryResult<T> = {
>UseQueryResult : Symbol(UseQueryResult, Decl(controlFlowAliasedDiscriminants.ts, 0, 0))
>T : Symbol(T, Decl(controlFlowAliasedDiscriminants.ts, 0, 20))
isSuccess: false;
>isSuccess : Symbol(isSuccess, Decl(controlFlowAliasedDiscriminants.ts, 0, 26))
data: undefined;
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 1, 21))
} | {
isSuccess: true;
>isSuccess : Symbol(isSuccess, Decl(controlFlowAliasedDiscriminants.ts, 3, 5))
data: T
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 4, 20))
>T : Symbol(T, Decl(controlFlowAliasedDiscriminants.ts, 0, 20))
};
function useQuery(): UseQueryResult<number> {
>useQuery : Symbol(useQuery, Decl(controlFlowAliasedDiscriminants.ts, 6, 2))
>UseQueryResult : Symbol(UseQueryResult, Decl(controlFlowAliasedDiscriminants.ts, 0, 0))
return {
isSuccess: false,
>isSuccess : Symbol(isSuccess, Decl(controlFlowAliasedDiscriminants.ts, 9, 12))
data: undefined,
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 10, 25))
>undefined : Symbol(undefined)
};
}
const { data: data1, isSuccess: isSuccess1 } = useQuery();
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 1, 21), Decl(controlFlowAliasedDiscriminants.ts, 4, 20))
>data1 : Symbol(data1, Decl(controlFlowAliasedDiscriminants.ts, 15, 7))
>isSuccess : Symbol(isSuccess, Decl(controlFlowAliasedDiscriminants.ts, 0, 26), Decl(controlFlowAliasedDiscriminants.ts, 3, 5))
>isSuccess1 : Symbol(isSuccess1, Decl(controlFlowAliasedDiscriminants.ts, 15, 20))
>useQuery : Symbol(useQuery, Decl(controlFlowAliasedDiscriminants.ts, 6, 2))
const { data: data2, isSuccess: isSuccess2 } = useQuery();
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 1, 21), Decl(controlFlowAliasedDiscriminants.ts, 4, 20))
>data2 : Symbol(data2, Decl(controlFlowAliasedDiscriminants.ts, 16, 7))
>isSuccess : Symbol(isSuccess, Decl(controlFlowAliasedDiscriminants.ts, 0, 26), Decl(controlFlowAliasedDiscriminants.ts, 3, 5))
>isSuccess2 : Symbol(isSuccess2, Decl(controlFlowAliasedDiscriminants.ts, 16, 20))
>useQuery : Symbol(useQuery, Decl(controlFlowAliasedDiscriminants.ts, 6, 2))
const { data: data3, isSuccess: isSuccess3 } = useQuery();
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 1, 21), Decl(controlFlowAliasedDiscriminants.ts, 4, 20))
>data3 : Symbol(data3, Decl(controlFlowAliasedDiscriminants.ts, 17, 7))
>isSuccess : Symbol(isSuccess, Decl(controlFlowAliasedDiscriminants.ts, 0, 26), Decl(controlFlowAliasedDiscriminants.ts, 3, 5))
>isSuccess3 : Symbol(isSuccess3, Decl(controlFlowAliasedDiscriminants.ts, 17, 20))
>useQuery : Symbol(useQuery, Decl(controlFlowAliasedDiscriminants.ts, 6, 2))
if (isSuccess1 && isSuccess2 && isSuccess3) {
>isSuccess1 : Symbol(isSuccess1, Decl(controlFlowAliasedDiscriminants.ts, 15, 20))
>isSuccess2 : Symbol(isSuccess2, Decl(controlFlowAliasedDiscriminants.ts, 16, 20))
>isSuccess3 : Symbol(isSuccess3, Decl(controlFlowAliasedDiscriminants.ts, 17, 20))
data1.toExponential(); // should ok
>data1.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>data1 : Symbol(data1, Decl(controlFlowAliasedDiscriminants.ts, 15, 7))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
data2.toExponential(); // should ok
>data2.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>data2 : Symbol(data2, Decl(controlFlowAliasedDiscriminants.ts, 16, 7))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
data3.toExponential(); // should ok
>data3.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>data3 : Symbol(data3, Decl(controlFlowAliasedDiscriminants.ts, 17, 7))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
}
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
>areSuccess : Symbol(areSuccess, Decl(controlFlowAliasedDiscriminants.ts, 25, 5))
>isSuccess1 : Symbol(isSuccess1, Decl(controlFlowAliasedDiscriminants.ts, 15, 20))
>isSuccess2 : Symbol(isSuccess2, Decl(controlFlowAliasedDiscriminants.ts, 16, 20))
>isSuccess3 : Symbol(isSuccess3, Decl(controlFlowAliasedDiscriminants.ts, 17, 20))
if (areSuccess) {
>areSuccess : Symbol(areSuccess, Decl(controlFlowAliasedDiscriminants.ts, 25, 5))
data1.toExponential(); // should ok
>data1.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>data1 : Symbol(data1, Decl(controlFlowAliasedDiscriminants.ts, 15, 7))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
data2.toExponential(); // should ok
>data2.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>data2 : Symbol(data2, Decl(controlFlowAliasedDiscriminants.ts, 16, 7))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
data3.toExponential(); // should ok
>data3.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>data3 : Symbol(data3, Decl(controlFlowAliasedDiscriminants.ts, 17, 7))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
}
{
let { data: data1, isSuccess: isSuccess1 } = useQuery();
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 1, 21), Decl(controlFlowAliasedDiscriminants.ts, 4, 20))
>data1 : Symbol(data1, Decl(controlFlowAliasedDiscriminants.ts, 33, 9))
>isSuccess : Symbol(isSuccess, Decl(controlFlowAliasedDiscriminants.ts, 0, 26), Decl(controlFlowAliasedDiscriminants.ts, 3, 5))
>isSuccess1 : Symbol(isSuccess1, Decl(controlFlowAliasedDiscriminants.ts, 33, 22))
>useQuery : Symbol(useQuery, Decl(controlFlowAliasedDiscriminants.ts, 6, 2))
let { data: data2, isSuccess: isSuccess2 } = useQuery();
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 1, 21), Decl(controlFlowAliasedDiscriminants.ts, 4, 20))
>data2 : Symbol(data2, Decl(controlFlowAliasedDiscriminants.ts, 34, 9))
>isSuccess : Symbol(isSuccess, Decl(controlFlowAliasedDiscriminants.ts, 0, 26), Decl(controlFlowAliasedDiscriminants.ts, 3, 5))
>isSuccess2 : Symbol(isSuccess2, Decl(controlFlowAliasedDiscriminants.ts, 34, 22))
>useQuery : Symbol(useQuery, Decl(controlFlowAliasedDiscriminants.ts, 6, 2))
const { data: data3, isSuccess: isSuccess3 } = useQuery();
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 1, 21), Decl(controlFlowAliasedDiscriminants.ts, 4, 20))
>data3 : Symbol(data3, Decl(controlFlowAliasedDiscriminants.ts, 35, 11))
>isSuccess : Symbol(isSuccess, Decl(controlFlowAliasedDiscriminants.ts, 0, 26), Decl(controlFlowAliasedDiscriminants.ts, 3, 5))
>isSuccess3 : Symbol(isSuccess3, Decl(controlFlowAliasedDiscriminants.ts, 35, 24))
>useQuery : Symbol(useQuery, Decl(controlFlowAliasedDiscriminants.ts, 6, 2))
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
>areSuccess : Symbol(areSuccess, Decl(controlFlowAliasedDiscriminants.ts, 36, 9))
>isSuccess1 : Symbol(isSuccess1, Decl(controlFlowAliasedDiscriminants.ts, 33, 22))
>isSuccess2 : Symbol(isSuccess2, Decl(controlFlowAliasedDiscriminants.ts, 34, 22))
>isSuccess3 : Symbol(isSuccess3, Decl(controlFlowAliasedDiscriminants.ts, 35, 24))
if (areSuccess) {
>areSuccess : Symbol(areSuccess, Decl(controlFlowAliasedDiscriminants.ts, 36, 9))
data1.toExponential(); // should error
>data1.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>data1 : Symbol(data1, Decl(controlFlowAliasedDiscriminants.ts, 33, 9))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
data2.toExponential(); // should error
>data2.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>data2 : Symbol(data2, Decl(controlFlowAliasedDiscriminants.ts, 34, 9))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
data3.toExponential(); // should ok
>data3.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>data3 : Symbol(data3, Decl(controlFlowAliasedDiscriminants.ts, 35, 11))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
}
}
declare function getArrayResult(): [true, number] | [false, undefined];
>getArrayResult : Symbol(getArrayResult, Decl(controlFlowAliasedDiscriminants.ts, 42, 1))
{
const [foo1, bar1] = getArrayResult();
>foo1 : Symbol(foo1, Decl(controlFlowAliasedDiscriminants.ts, 46, 11))
>bar1 : Symbol(bar1, Decl(controlFlowAliasedDiscriminants.ts, 46, 16))
>getArrayResult : Symbol(getArrayResult, Decl(controlFlowAliasedDiscriminants.ts, 42, 1))
const [foo2, bar2] = getArrayResult();
>foo2 : Symbol(foo2, Decl(controlFlowAliasedDiscriminants.ts, 47, 11))
>bar2 : Symbol(bar2, Decl(controlFlowAliasedDiscriminants.ts, 47, 16))
>getArrayResult : Symbol(getArrayResult, Decl(controlFlowAliasedDiscriminants.ts, 42, 1))
const [foo3, bar3] = getArrayResult();
>foo3 : Symbol(foo3, Decl(controlFlowAliasedDiscriminants.ts, 48, 11))
>bar3 : Symbol(bar3, Decl(controlFlowAliasedDiscriminants.ts, 48, 16))
>getArrayResult : Symbol(getArrayResult, Decl(controlFlowAliasedDiscriminants.ts, 42, 1))
const arrayAllSuccess = foo1 && foo2 && foo3;
>arrayAllSuccess : Symbol(arrayAllSuccess, Decl(controlFlowAliasedDiscriminants.ts, 49, 9))
>foo1 : Symbol(foo1, Decl(controlFlowAliasedDiscriminants.ts, 46, 11))
>foo2 : Symbol(foo2, Decl(controlFlowAliasedDiscriminants.ts, 47, 11))
>foo3 : Symbol(foo3, Decl(controlFlowAliasedDiscriminants.ts, 48, 11))
if (arrayAllSuccess) {
>arrayAllSuccess : Symbol(arrayAllSuccess, Decl(controlFlowAliasedDiscriminants.ts, 49, 9))
bar1.toExponential(); // should ok
>bar1.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>bar1 : Symbol(bar1, Decl(controlFlowAliasedDiscriminants.ts, 46, 16))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
bar2.toExponential(); // should ok
>bar2.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>bar2 : Symbol(bar2, Decl(controlFlowAliasedDiscriminants.ts, 47, 16))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
bar3.toExponential(); // should ok
>bar3.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>bar3 : Symbol(bar3, Decl(controlFlowAliasedDiscriminants.ts, 48, 16))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
}
}
{
const [foo1, bar1] = getArrayResult();
>foo1 : Symbol(foo1, Decl(controlFlowAliasedDiscriminants.ts, 58, 11))
>bar1 : Symbol(bar1, Decl(controlFlowAliasedDiscriminants.ts, 58, 16))
>getArrayResult : Symbol(getArrayResult, Decl(controlFlowAliasedDiscriminants.ts, 42, 1))
let [foo2, bar2] = getArrayResult();
>foo2 : Symbol(foo2, Decl(controlFlowAliasedDiscriminants.ts, 59, 9))
>bar2 : Symbol(bar2, Decl(controlFlowAliasedDiscriminants.ts, 59, 14))
>getArrayResult : Symbol(getArrayResult, Decl(controlFlowAliasedDiscriminants.ts, 42, 1))
let [foo3, bar3] = getArrayResult();
>foo3 : Symbol(foo3, Decl(controlFlowAliasedDiscriminants.ts, 60, 9))
>bar3 : Symbol(bar3, Decl(controlFlowAliasedDiscriminants.ts, 60, 14))
>getArrayResult : Symbol(getArrayResult, Decl(controlFlowAliasedDiscriminants.ts, 42, 1))
const arrayAllSuccess = foo1 && foo2 && foo3;
>arrayAllSuccess : Symbol(arrayAllSuccess, Decl(controlFlowAliasedDiscriminants.ts, 61, 9))
>foo1 : Symbol(foo1, Decl(controlFlowAliasedDiscriminants.ts, 58, 11))
>foo2 : Symbol(foo2, Decl(controlFlowAliasedDiscriminants.ts, 59, 9))
>foo3 : Symbol(foo3, Decl(controlFlowAliasedDiscriminants.ts, 60, 9))
if (arrayAllSuccess) {
>arrayAllSuccess : Symbol(arrayAllSuccess, Decl(controlFlowAliasedDiscriminants.ts, 61, 9))
bar1.toExponential(); // should ok
>bar1.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>bar1 : Symbol(bar1, Decl(controlFlowAliasedDiscriminants.ts, 58, 16))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
bar2.toExponential(); // should error
>bar2.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>bar2 : Symbol(bar2, Decl(controlFlowAliasedDiscriminants.ts, 59, 14))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
bar3.toExponential(); // should error
>bar3.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>bar3 : Symbol(bar3, Decl(controlFlowAliasedDiscriminants.ts, 60, 14))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
}
}
type Nested = {
>Nested : Symbol(Nested, Decl(controlFlowAliasedDiscriminants.ts, 67, 1))
type: 'string';
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 69, 15))
resp: {
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19))
data: string
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 71, 11))
}
} | {
type: 'number';
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 74, 5))
resp: {
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 75, 19))
data: number;
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 76, 11))
}
}
{
let resp!: Nested;
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 82, 7))
>Nested : Symbol(Nested, Decl(controlFlowAliasedDiscriminants.ts, 67, 1))
const { resp: { data }, type } = resp;
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19), Decl(controlFlowAliasedDiscriminants.ts, 75, 19))
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 83, 19))
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 83, 27))
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 82, 7))
if (type === 'string') {
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 83, 27))
data satisfies string;
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 83, 19))
}
if (resp.type === 'string') {
>resp.type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 69, 15), Decl(controlFlowAliasedDiscriminants.ts, 74, 5))
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 82, 7))
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 69, 15), Decl(controlFlowAliasedDiscriminants.ts, 74, 5))
resp.resp.data satisfies string;
>resp.resp.data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 71, 11))
>resp.resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19))
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 82, 7))
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19))
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 71, 11))
}
}
{
let resp!: Nested;
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 94, 7))
>Nested : Symbol(Nested, Decl(controlFlowAliasedDiscriminants.ts, 67, 1))
const { resp: { data: dataAlias }, type } = resp;
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19), Decl(controlFlowAliasedDiscriminants.ts, 75, 19))
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 71, 11), Decl(controlFlowAliasedDiscriminants.ts, 76, 11))
>dataAlias : Symbol(dataAlias, Decl(controlFlowAliasedDiscriminants.ts, 95, 19))
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 95, 38))
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 94, 7))
if (type === 'string') {
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 95, 38))
dataAlias satisfies string;
>dataAlias : Symbol(dataAlias, Decl(controlFlowAliasedDiscriminants.ts, 95, 19))
}
if (resp.type === 'string') {
>resp.type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 69, 15), Decl(controlFlowAliasedDiscriminants.ts, 74, 5))
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 94, 7))
>type : Symbol(type, Decl(controlFlowAliasedDiscriminants.ts, 69, 15), Decl(controlFlowAliasedDiscriminants.ts, 74, 5))
resp.resp.data satisfies string;
>resp.resp.data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 71, 11))
>resp.resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19))
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 94, 7))
>resp : Symbol(resp, Decl(controlFlowAliasedDiscriminants.ts, 70, 19))
>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 71, 11))
}
}

View File

@ -0,0 +1,378 @@
//// [tests/cases/compiler/controlFlowAliasedDiscriminants.ts] ////
=== controlFlowAliasedDiscriminants.ts ===
type UseQueryResult<T> = {
>UseQueryResult : UseQueryResult<T>
isSuccess: false;
>isSuccess : false
>false : false
data: undefined;
>data : undefined
} | {
isSuccess: true;
>isSuccess : true
>true : true
data: T
>data : T
};
function useQuery(): UseQueryResult<number> {
>useQuery : () => UseQueryResult<number>
return {
>{ isSuccess: false, data: undefined, } : { isSuccess: false; data: undefined; }
isSuccess: false,
>isSuccess : false
>false : false
data: undefined,
>data : undefined
>undefined : undefined
};
}
const { data: data1, isSuccess: isSuccess1 } = useQuery();
>data : any
>data1 : number | undefined
>isSuccess : any
>isSuccess1 : boolean
>useQuery() : UseQueryResult<number>
>useQuery : () => UseQueryResult<number>
const { data: data2, isSuccess: isSuccess2 } = useQuery();
>data : any
>data2 : number | undefined
>isSuccess : any
>isSuccess2 : boolean
>useQuery() : UseQueryResult<number>
>useQuery : () => UseQueryResult<number>
const { data: data3, isSuccess: isSuccess3 } = useQuery();
>data : any
>data3 : number | undefined
>isSuccess : any
>isSuccess3 : boolean
>useQuery() : UseQueryResult<number>
>useQuery : () => UseQueryResult<number>
if (isSuccess1 && isSuccess2 && isSuccess3) {
>isSuccess1 && isSuccess2 && isSuccess3 : boolean
>isSuccess1 && isSuccess2 : boolean
>isSuccess1 : boolean
>isSuccess2 : boolean
>isSuccess3 : boolean
data1.toExponential(); // should ok
>data1.toExponential() : string
>data1.toExponential : (fractionDigits?: number | undefined) => string
>data1 : number
>toExponential : (fractionDigits?: number | undefined) => string
data2.toExponential(); // should ok
>data2.toExponential() : string
>data2.toExponential : (fractionDigits?: number | undefined) => string
>data2 : number
>toExponential : (fractionDigits?: number | undefined) => string
data3.toExponential(); // should ok
>data3.toExponential() : string
>data3.toExponential : (fractionDigits?: number | undefined) => string
>data3 : number
>toExponential : (fractionDigits?: number | undefined) => string
}
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
>areSuccess : boolean
>isSuccess1 && isSuccess2 && isSuccess3 : boolean
>isSuccess1 && isSuccess2 : boolean
>isSuccess1 : boolean
>isSuccess2 : boolean
>isSuccess3 : boolean
if (areSuccess) {
>areSuccess : boolean
data1.toExponential(); // should ok
>data1.toExponential() : string
>data1.toExponential : (fractionDigits?: number | undefined) => string
>data1 : number
>toExponential : (fractionDigits?: number | undefined) => string
data2.toExponential(); // should ok
>data2.toExponential() : string
>data2.toExponential : (fractionDigits?: number | undefined) => string
>data2 : number
>toExponential : (fractionDigits?: number | undefined) => string
data3.toExponential(); // should ok
>data3.toExponential() : string
>data3.toExponential : (fractionDigits?: number | undefined) => string
>data3 : number
>toExponential : (fractionDigits?: number | undefined) => string
}
{
let { data: data1, isSuccess: isSuccess1 } = useQuery();
>data : any
>data1 : number | undefined
>isSuccess : any
>isSuccess1 : boolean
>useQuery() : UseQueryResult<number>
>useQuery : () => UseQueryResult<number>
let { data: data2, isSuccess: isSuccess2 } = useQuery();
>data : any
>data2 : number | undefined
>isSuccess : any
>isSuccess2 : boolean
>useQuery() : UseQueryResult<number>
>useQuery : () => UseQueryResult<number>
const { data: data3, isSuccess: isSuccess3 } = useQuery();
>data : any
>data3 : number | undefined
>isSuccess : any
>isSuccess3 : boolean
>useQuery() : UseQueryResult<number>
>useQuery : () => UseQueryResult<number>
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
>areSuccess : boolean
>isSuccess1 && isSuccess2 && isSuccess3 : boolean
>isSuccess1 && isSuccess2 : boolean
>isSuccess1 : boolean
>isSuccess2 : boolean
>isSuccess3 : boolean
if (areSuccess) {
>areSuccess : boolean
data1.toExponential(); // should error
>data1.toExponential() : string
>data1.toExponential : (fractionDigits?: number | undefined) => string
>data1 : number | undefined
>toExponential : (fractionDigits?: number | undefined) => string
data2.toExponential(); // should error
>data2.toExponential() : string
>data2.toExponential : (fractionDigits?: number | undefined) => string
>data2 : number | undefined
>toExponential : (fractionDigits?: number | undefined) => string
data3.toExponential(); // should ok
>data3.toExponential() : string
>data3.toExponential : (fractionDigits?: number | undefined) => string
>data3 : number
>toExponential : (fractionDigits?: number | undefined) => string
}
}
declare function getArrayResult(): [true, number] | [false, undefined];
>getArrayResult : () => [true, number] | [false, undefined]
>true : true
>false : false
{
const [foo1, bar1] = getArrayResult();
>foo1 : boolean
>bar1 : number | undefined
>getArrayResult() : [true, number] | [false, undefined]
>getArrayResult : () => [true, number] | [false, undefined]
const [foo2, bar2] = getArrayResult();
>foo2 : boolean
>bar2 : number | undefined
>getArrayResult() : [true, number] | [false, undefined]
>getArrayResult : () => [true, number] | [false, undefined]
const [foo3, bar3] = getArrayResult();
>foo3 : boolean
>bar3 : number | undefined
>getArrayResult() : [true, number] | [false, undefined]
>getArrayResult : () => [true, number] | [false, undefined]
const arrayAllSuccess = foo1 && foo2 && foo3;
>arrayAllSuccess : boolean
>foo1 && foo2 && foo3 : boolean
>foo1 && foo2 : boolean
>foo1 : boolean
>foo2 : boolean
>foo3 : boolean
if (arrayAllSuccess) {
>arrayAllSuccess : boolean
bar1.toExponential(); // should ok
>bar1.toExponential() : string
>bar1.toExponential : (fractionDigits?: number | undefined) => string
>bar1 : number
>toExponential : (fractionDigits?: number | undefined) => string
bar2.toExponential(); // should ok
>bar2.toExponential() : string
>bar2.toExponential : (fractionDigits?: number | undefined) => string
>bar2 : number
>toExponential : (fractionDigits?: number | undefined) => string
bar3.toExponential(); // should ok
>bar3.toExponential() : string
>bar3.toExponential : (fractionDigits?: number | undefined) => string
>bar3 : number
>toExponential : (fractionDigits?: number | undefined) => string
}
}
{
const [foo1, bar1] = getArrayResult();
>foo1 : boolean
>bar1 : number | undefined
>getArrayResult() : [true, number] | [false, undefined]
>getArrayResult : () => [true, number] | [false, undefined]
let [foo2, bar2] = getArrayResult();
>foo2 : boolean
>bar2 : number | undefined
>getArrayResult() : [true, number] | [false, undefined]
>getArrayResult : () => [true, number] | [false, undefined]
let [foo3, bar3] = getArrayResult();
>foo3 : boolean
>bar3 : number | undefined
>getArrayResult() : [true, number] | [false, undefined]
>getArrayResult : () => [true, number] | [false, undefined]
const arrayAllSuccess = foo1 && foo2 && foo3;
>arrayAllSuccess : boolean
>foo1 && foo2 && foo3 : boolean
>foo1 && foo2 : boolean
>foo1 : boolean
>foo2 : boolean
>foo3 : boolean
if (arrayAllSuccess) {
>arrayAllSuccess : boolean
bar1.toExponential(); // should ok
>bar1.toExponential() : string
>bar1.toExponential : (fractionDigits?: number | undefined) => string
>bar1 : number
>toExponential : (fractionDigits?: number | undefined) => string
bar2.toExponential(); // should error
>bar2.toExponential() : string
>bar2.toExponential : (fractionDigits?: number | undefined) => string
>bar2 : number | undefined
>toExponential : (fractionDigits?: number | undefined) => string
bar3.toExponential(); // should error
>bar3.toExponential() : string
>bar3.toExponential : (fractionDigits?: number | undefined) => string
>bar3 : number | undefined
>toExponential : (fractionDigits?: number | undefined) => string
}
}
type Nested = {
>Nested : { type: 'string'; resp: { data: string;}; } | { type: 'number'; resp: { data: number;}; }
type: 'string';
>type : "string"
resp: {
>resp : { data: string; }
data: string
>data : string
}
} | {
type: 'number';
>type : "number"
resp: {
>resp : { data: number; }
data: number;
>data : number
}
}
{
let resp!: Nested;
>resp : Nested
const { resp: { data }, type } = resp;
>resp : any
>data : string | number
>type : "string" | "number"
>resp : Nested
if (type === 'string') {
>type === 'string' : boolean
>type : "string" | "number"
>'string' : "string"
data satisfies string;
>data satisfies string : string | number
>data : string | number
}
if (resp.type === 'string') {
>resp.type === 'string' : boolean
>resp.type : "string" | "number"
>resp : Nested
>type : "string" | "number"
>'string' : "string"
resp.resp.data satisfies string;
>resp.resp.data satisfies string : string
>resp.resp.data : string
>resp.resp : { data: string; }
>resp : { type: "string"; resp: { data: string; }; }
>resp : { data: string; }
>data : string
}
}
{
let resp!: Nested;
>resp : Nested
const { resp: { data: dataAlias }, type } = resp;
>resp : any
>data : any
>dataAlias : string | number
>type : "string" | "number"
>resp : Nested
if (type === 'string') {
>type === 'string' : boolean
>type : "string" | "number"
>'string' : "string"
dataAlias satisfies string;
>dataAlias satisfies string : string | number
>dataAlias : string | number
}
if (resp.type === 'string') {
>resp.type === 'string' : boolean
>resp.type : "string" | "number"
>resp : Nested
>type : "string" | "number"
>'string' : "string"
resp.resp.data satisfies string;
>resp.resp.data satisfies string : string
>resp.resp.data : string
>resp.resp : { data: string; }
>resp : { type: "string"; resp: { data: string; }; }
>resp : { data: string; }
>data : string
}
}

View File

@ -0,0 +1,106 @@
// @strictNullChecks: true
// @noImplicitAny: true
type UseQueryResult<T> = {
isSuccess: false;
data: undefined;
} | {
isSuccess: true;
data: T
};
function useQuery(): UseQueryResult<number> {
return {
isSuccess: false,
data: undefined,
};
}
const { data: data1, isSuccess: isSuccess1 } = useQuery();
const { data: data2, isSuccess: isSuccess2 } = useQuery();
const { data: data3, isSuccess: isSuccess3 } = useQuery();
if (isSuccess1 && isSuccess2 && isSuccess3) {
data1.toExponential(); // should ok
data2.toExponential(); // should ok
data3.toExponential(); // should ok
}
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
if (areSuccess) {
data1.toExponential(); // should ok
data2.toExponential(); // should ok
data3.toExponential(); // should ok
}
{
let { data: data1, isSuccess: isSuccess1 } = useQuery();
let { data: data2, isSuccess: isSuccess2 } = useQuery();
const { data: data3, isSuccess: isSuccess3 } = useQuery();
const areSuccess = isSuccess1 && isSuccess2 && isSuccess3;
if (areSuccess) {
data1.toExponential(); // should error
data2.toExponential(); // should error
data3.toExponential(); // should ok
}
}
declare function getArrayResult(): [true, number] | [false, undefined];
{
const [foo1, bar1] = getArrayResult();
const [foo2, bar2] = getArrayResult();
const [foo3, bar3] = getArrayResult();
const arrayAllSuccess = foo1 && foo2 && foo3;
if (arrayAllSuccess) {
bar1.toExponential(); // should ok
bar2.toExponential(); // should ok
bar3.toExponential(); // should ok
}
}
{
const [foo1, bar1] = getArrayResult();
let [foo2, bar2] = getArrayResult();
let [foo3, bar3] = getArrayResult();
const arrayAllSuccess = foo1 && foo2 && foo3;
if (arrayAllSuccess) {
bar1.toExponential(); // should ok
bar2.toExponential(); // should error
bar3.toExponential(); // should error
}
}
type Nested = {
type: 'string';
resp: {
data: string
}
} | {
type: 'number';
resp: {
data: number;
}
}
{
let resp!: Nested;
const { resp: { data }, type } = resp;
if (type === 'string') {
data satisfies string;
}
if (resp.type === 'string') {
resp.resp.data satisfies string;
}
}
{
let resp!: Nested;
const { resp: { data: dataAlias }, type } = resp;
if (type === 'string') {
dataAlias satisfies string;
}
if (resp.type === 'string') {
resp.resp.data satisfies string;
}
}