Narrow QualifiedName inside typeof (#42540)

Previously this wasn't narrowed at all. Now there is control flow and
code in isMatchingReference.
This commit is contained in:
Nathan Shively-Sanders
2021-01-28 15:19:01 -08:00
committed by GitHub
parent 5a21291b7c
commit 9dbfaeef2d
6 changed files with 89 additions and 5 deletions

View File

@@ -2540,6 +2540,11 @@ namespace ts {
node.flowNode = currentFlow;
}
return checkContextualIdentifier(<Identifier>node);
case SyntaxKind.QualifiedName:
if (currentFlow && parent.kind === SyntaxKind.TypeQuery) {
node.flowNode = currentFlow;
}
break;
case SyntaxKind.SuperKeyword:
node.flowNode = currentFlow;
break;

View File

@@ -21289,8 +21289,12 @@ namespace ts {
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
return isAccessExpression(target) &&
getAccessedPropertyName(<AccessExpression>source) === getAccessedPropertyName(target) &&
isMatchingReference((<AccessExpression>source).expression, target.expression);
getAccessedPropertyName(source as AccessExpression) === getAccessedPropertyName(target) &&
isMatchingReference((source as AccessExpression).expression, target.expression);
case SyntaxKind.QualifiedName:
return isAccessExpression(target) &&
(source as QualifiedName).right.escapedText === getAccessedPropertyName(target) &&
isMatchingReference((source as QualifiedName).left, target.expression);
case SyntaxKind.BinaryExpression:
return (isBinaryExpression(source) && source.operatorToken.kind === SyntaxKind.CommaToken && isMatchingReference(source.right, target));
}
@@ -26421,8 +26425,7 @@ namespace ts {
// assignment target, and the referenced property was declared as a variable, property,
// accessor, or optional method.
const assignmentKind = getAssignmentTargetKind(node);
if (!isAccessExpression(node) ||
assignmentKind === AssignmentKind.Definite ||
if (assignmentKind === AssignmentKind.Definite ||
prop && !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) && !(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) {
return propType;
}
@@ -26434,7 +26437,7 @@ namespace ts {
// and if we are in a constructor of the same class as the property declaration, assume that
// the property is uninitialized at the top of the control flow.
let assumeUninitialized = false;
if (strictNullChecks && strictPropertyInitialization && node.expression.kind === SyntaxKind.ThisKeyword) {
if (strictNullChecks && strictPropertyInitialization && isAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword) {
const declaration = prop && prop.valueDeclaration;
if (declaration && isInstancePropertyWithoutInitializer(declaration)) {
const flowContainer = getControlFlowContainer(node);

View File

@@ -51,6 +51,15 @@ function d<T extends string>(data: string | T): never {
return data;
}
}
interface I<T> {
p: T;
}
function e(x: I<"A" | "B">) {
if (x.p === "A") {
let a: "A" = (null as unknown as typeof x.p)
}
}
//// [controlFlowIfStatement.js]
@@ -104,3 +113,8 @@ function d(data) {
return data;
}
}
function e(x) {
if (x.p === "A") {
var a_1 = null;
}
}

View File

@@ -110,3 +110,29 @@ function d<T extends string>(data: string | T): never {
}
}
interface I<T> {
>I : Symbol(I, Decl(controlFlowIfStatement.ts, 51, 1))
>T : Symbol(T, Decl(controlFlowIfStatement.ts, 53, 12))
p: T;
>p : Symbol(I.p, Decl(controlFlowIfStatement.ts, 53, 16))
>T : Symbol(T, Decl(controlFlowIfStatement.ts, 53, 12))
}
function e(x: I<"A" | "B">) {
>e : Symbol(e, Decl(controlFlowIfStatement.ts, 55, 1))
>x : Symbol(x, Decl(controlFlowIfStatement.ts, 56, 11))
>I : Symbol(I, Decl(controlFlowIfStatement.ts, 51, 1))
if (x.p === "A") {
>x.p : Symbol(I.p, Decl(controlFlowIfStatement.ts, 53, 16))
>x : Symbol(x, Decl(controlFlowIfStatement.ts, 56, 11))
>p : Symbol(I.p, Decl(controlFlowIfStatement.ts, 53, 16))
let a: "A" = (null as unknown as typeof x.p)
>a : Symbol(a, Decl(controlFlowIfStatement.ts, 58, 11))
>x.p : Symbol(I.p, Decl(controlFlowIfStatement.ts, 53, 16))
>x : Symbol(x, Decl(controlFlowIfStatement.ts, 56, 11))
>p : Symbol(I.p, Decl(controlFlowIfStatement.ts, 53, 16))
}
}

View File

@@ -132,3 +132,30 @@ function d<T extends string>(data: string | T): never {
}
}
interface I<T> {
p: T;
>p : T
}
function e(x: I<"A" | "B">) {
>e : (x: I<"A" | "B">) => void
>x : I<"A" | "B">
if (x.p === "A") {
>x.p === "A" : boolean
>x.p : "A" | "B"
>x : I<"A" | "B">
>p : "A" | "B"
>"A" : "A"
let a: "A" = (null as unknown as typeof x.p)
>a : "A"
>(null as unknown as typeof x.p) : "A"
>null as unknown as typeof x.p : "A"
>null as unknown : unknown
>null : null
>x.p : "A"
>x : I<"A" | "B">
>p : "A"
}
}

View File

@@ -52,3 +52,12 @@ function d<T extends string>(data: string | T): never {
return data;
}
}
interface I<T> {
p: T;
}
function e(x: I<"A" | "B">) {
if (x.p === "A") {
let a: "A" = (null as unknown as typeof x.p)
}
}