mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-29 16:29:19 -05:00
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:
committed by
GitHub
parent
5a21291b7c
commit
9dbfaeef2d
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user