Narrow via discriminant property through optional chain (#42450)

* Naive attempt at narrowing via discriminant property through optional chain

* Clean up test
This commit is contained in:
Andrew Branch
2021-01-25 09:29:51 -08:00
committed by GitHub
parent 290af69b73
commit 89c173fddc
7 changed files with 149 additions and 8 deletions
+4 -1
View File
@@ -22599,10 +22599,13 @@ namespace ts {
if (propName === undefined) {
return type;
}
const propType = getTypeOfPropertyOfType(type, propName);
const includesUndefined = strictNullChecks && maybeTypeOfKind(type, TypeFlags.Undefined);
const removeOptional = includesUndefined && isOptionalChain(access);
let propType = getTypeOfPropertyOfType(removeOptional ? getTypeWithFacts(type, TypeFacts.NEUndefined) : type, propName);
if (!propType) {
return type;
}
propType = removeOptional ? getOptionalType(propType) : propType;
const narrowedPropType = narrowType(propType);
return filterType(type, t => {
const discriminantType = getTypeOfPropertyOrIndexSignature(t, propName);
@@ -200,14 +200,14 @@ else {
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
o3?.x;
>o3?.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
>o3?.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 41))
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 41))
o3.x;
>o3.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
>o3.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 41))
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 41))
}
o3;
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
@@ -223,16 +223,16 @@ if (o3?.x === 1) {
}
else {
o3;
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
>o3 : { x: 2; y: number; } | undefined
o3?.x;
>o3?.x : 2 | undefined
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
>o3 : { x: 2; y: number; } | undefined
>x : 2 | undefined
o3.x;
>o3.x : 2
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
>o3 : { x: 2; y: number; } | undefined
>x : 2
}
o3;
@@ -0,0 +1,30 @@
//// [controlFlowOptionalChain2.ts]
type A = {
type: 'A';
name: string;
}
type B = {
type: 'B';
}
function funcTwo(arg: A | B | undefined) {
if (arg?.type === 'B') {
arg; // `B`
return;
}
arg;
arg?.name;
}
//// [controlFlowOptionalChain2.js]
function funcTwo(arg) {
if ((arg === null || arg === void 0 ? void 0 : arg.type) === 'B') {
arg; // `B`
return;
}
arg;
arg === null || arg === void 0 ? void 0 : arg.name;
}
@@ -0,0 +1,44 @@
=== tests/cases/conformance/controlFlow/controlFlowOptionalChain2.ts ===
type A = {
>A : Symbol(A, Decl(controlFlowOptionalChain2.ts, 0, 0))
type: 'A';
>type : Symbol(type, Decl(controlFlowOptionalChain2.ts, 0, 10))
name: string;
>name : Symbol(name, Decl(controlFlowOptionalChain2.ts, 1, 12))
}
type B = {
>B : Symbol(B, Decl(controlFlowOptionalChain2.ts, 3, 1))
type: 'B';
>type : Symbol(type, Decl(controlFlowOptionalChain2.ts, 5, 10))
}
function funcTwo(arg: A | B | undefined) {
>funcTwo : Symbol(funcTwo, Decl(controlFlowOptionalChain2.ts, 7, 1))
>arg : Symbol(arg, Decl(controlFlowOptionalChain2.ts, 9, 17))
>A : Symbol(A, Decl(controlFlowOptionalChain2.ts, 0, 0))
>B : Symbol(B, Decl(controlFlowOptionalChain2.ts, 3, 1))
if (arg?.type === 'B') {
>arg?.type : Symbol(type, Decl(controlFlowOptionalChain2.ts, 0, 10), Decl(controlFlowOptionalChain2.ts, 5, 10))
>arg : Symbol(arg, Decl(controlFlowOptionalChain2.ts, 9, 17))
>type : Symbol(type, Decl(controlFlowOptionalChain2.ts, 0, 10), Decl(controlFlowOptionalChain2.ts, 5, 10))
arg; // `B`
>arg : Symbol(arg, Decl(controlFlowOptionalChain2.ts, 9, 17))
return;
}
arg;
>arg : Symbol(arg, Decl(controlFlowOptionalChain2.ts, 9, 17))
arg?.name;
>arg?.name : Symbol(name, Decl(controlFlowOptionalChain2.ts, 1, 12))
>arg : Symbol(arg, Decl(controlFlowOptionalChain2.ts, 9, 17))
>name : Symbol(name, Decl(controlFlowOptionalChain2.ts, 1, 12))
}
@@ -0,0 +1,44 @@
=== tests/cases/conformance/controlFlow/controlFlowOptionalChain2.ts ===
type A = {
>A : A
type: 'A';
>type : "A"
name: string;
>name : string
}
type B = {
>B : B
type: 'B';
>type : "B"
}
function funcTwo(arg: A | B | undefined) {
>funcTwo : (arg: A | B | undefined) => void
>arg : A | B | undefined
if (arg?.type === 'B') {
>arg?.type === 'B' : boolean
>arg?.type : "A" | "B" | undefined
>arg : A | B | undefined
>type : "A" | "B" | undefined
>'B' : "B"
arg; // `B`
>arg : B
return;
}
arg;
>arg : A | undefined
arg?.name;
>arg?.name : string | undefined
>arg : A | undefined
>name : string | undefined
}
@@ -0,0 +1,20 @@
// @strictNullChecks: true
type A = {
type: 'A';
name: string;
}
type B = {
type: 'B';
}
function funcTwo(arg: A | B | undefined) {
if (arg?.type === 'B') {
arg; // `B`
return;
}
arg;
arg?.name;
}