mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-10 21:07:52 -05:00
Allow private symbols to be control flow narrowed (#39978)
* Allow private symbols to be control flow narrowed * Add test with narrowing of inferred control flow type for completeness * Reformat long line
This commit is contained in:
@@ -831,6 +831,7 @@ namespace ts {
|
||||
function isNarrowingExpression(expr: Expression): boolean {
|
||||
switch (expr.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.PrivateIdentifier:
|
||||
case SyntaxKind.ThisKeyword:
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
@@ -850,7 +851,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isNarrowableReference(expr: Expression): boolean {
|
||||
return expr.kind === SyntaxKind.Identifier || expr.kind === SyntaxKind.ThisKeyword || expr.kind === SyntaxKind.SuperKeyword ||
|
||||
return expr.kind === SyntaxKind.Identifier || expr.kind === SyntaxKind.PrivateIdentifier || expr.kind === SyntaxKind.ThisKeyword || expr.kind === SyntaxKind.SuperKeyword ||
|
||||
(isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) && isNarrowableReference(expr.expression) ||
|
||||
isElementAccessExpression(expr) && isStringOrNumericLiteralLike(expr.argumentExpression) && isNarrowableReference(expr.expression) ||
|
||||
isAssignmentExpression(expr) && isNarrowableReference(expr.left);
|
||||
|
||||
@@ -8023,7 +8023,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getFlowTypeInConstructor(symbol: Symbol, constructor: ConstructorDeclaration) {
|
||||
const reference = factory.createPropertyAccessExpression(factory.createThis(), unescapeLeadingUnderscores(symbol.escapedName));
|
||||
const accessName = startsWith(symbol.escapedName as string, "__#")
|
||||
? factory.createPrivateIdentifier((symbol.escapedName as string).split("@")[1])
|
||||
: unescapeLeadingUnderscores(symbol.escapedName);
|
||||
const reference = factory.createPropertyAccessExpression(factory.createThis(), accessName);
|
||||
setParent(reference.expression, reference);
|
||||
setParent(reference, constructor);
|
||||
reference.flowNode = constructor.returnFlowNode;
|
||||
@@ -20232,6 +20235,7 @@ namespace ts {
|
||||
}
|
||||
switch (source.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.PrivateIdentifier:
|
||||
return target.kind === SyntaxKind.Identifier && getResolvedSymbol(<Identifier>source) === getResolvedSymbol(<Identifier>target) ||
|
||||
(target.kind === SyntaxKind.VariableDeclaration || target.kind === SyntaxKind.BindingElement) &&
|
||||
getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(<Identifier>source)) === getSymbolOfNode(target);
|
||||
|
||||
51
tests/baselines/reference/controlFlowPrivateClassField.js
Normal file
51
tests/baselines/reference/controlFlowPrivateClassField.js
Normal file
@@ -0,0 +1,51 @@
|
||||
//// [controlFlowPrivateClassField.ts]
|
||||
class Example {
|
||||
#test;
|
||||
|
||||
constructor(test: number) {
|
||||
this.#test = test;
|
||||
}
|
||||
|
||||
get test() {
|
||||
return this.#test
|
||||
}
|
||||
}
|
||||
|
||||
class Example2 {
|
||||
#test;
|
||||
|
||||
constructor(test: number | undefined) {
|
||||
this.#test = test;
|
||||
}
|
||||
|
||||
get test() {
|
||||
if (this.#test) {
|
||||
return this.#test
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//// [controlFlowPrivateClassField.js]
|
||||
"use strict";
|
||||
class Example {
|
||||
constructor(test) {
|
||||
this.#test = test;
|
||||
}
|
||||
#test;
|
||||
get test() {
|
||||
return this.#test;
|
||||
}
|
||||
}
|
||||
class Example2 {
|
||||
constructor(test) {
|
||||
this.#test = test;
|
||||
}
|
||||
#test;
|
||||
get test() {
|
||||
if (this.#test) {
|
||||
return this.#test;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
=== tests/cases/compiler/controlFlowPrivateClassField.ts ===
|
||||
class Example {
|
||||
>Example : Symbol(Example, Decl(controlFlowPrivateClassField.ts, 0, 0))
|
||||
|
||||
#test;
|
||||
>#test : Symbol(Example.#test, Decl(controlFlowPrivateClassField.ts, 0, 15))
|
||||
|
||||
constructor(test: number) {
|
||||
>test : Symbol(test, Decl(controlFlowPrivateClassField.ts, 3, 16))
|
||||
|
||||
this.#test = test;
|
||||
>this.#test : Symbol(Example.#test, Decl(controlFlowPrivateClassField.ts, 0, 15))
|
||||
>this : Symbol(Example, Decl(controlFlowPrivateClassField.ts, 0, 0))
|
||||
>test : Symbol(test, Decl(controlFlowPrivateClassField.ts, 3, 16))
|
||||
}
|
||||
|
||||
get test() {
|
||||
>test : Symbol(Example.test, Decl(controlFlowPrivateClassField.ts, 5, 5))
|
||||
|
||||
return this.#test
|
||||
>this.#test : Symbol(Example.#test, Decl(controlFlowPrivateClassField.ts, 0, 15))
|
||||
>this : Symbol(Example, Decl(controlFlowPrivateClassField.ts, 0, 0))
|
||||
}
|
||||
}
|
||||
|
||||
class Example2 {
|
||||
>Example2 : Symbol(Example2, Decl(controlFlowPrivateClassField.ts, 10, 1))
|
||||
|
||||
#test;
|
||||
>#test : Symbol(Example2.#test, Decl(controlFlowPrivateClassField.ts, 12, 16))
|
||||
|
||||
constructor(test: number | undefined) {
|
||||
>test : Symbol(test, Decl(controlFlowPrivateClassField.ts, 15, 16))
|
||||
|
||||
this.#test = test;
|
||||
>this.#test : Symbol(Example2.#test, Decl(controlFlowPrivateClassField.ts, 12, 16))
|
||||
>this : Symbol(Example2, Decl(controlFlowPrivateClassField.ts, 10, 1))
|
||||
>test : Symbol(test, Decl(controlFlowPrivateClassField.ts, 15, 16))
|
||||
}
|
||||
|
||||
get test() {
|
||||
>test : Symbol(Example2.test, Decl(controlFlowPrivateClassField.ts, 17, 5))
|
||||
|
||||
if (this.#test) {
|
||||
>this.#test : Symbol(Example2.#test, Decl(controlFlowPrivateClassField.ts, 12, 16))
|
||||
>this : Symbol(Example2, Decl(controlFlowPrivateClassField.ts, 10, 1))
|
||||
|
||||
return this.#test
|
||||
>this.#test : Symbol(Example2.#test, Decl(controlFlowPrivateClassField.ts, 12, 16))
|
||||
>this : Symbol(Example2, Decl(controlFlowPrivateClassField.ts, 10, 1))
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
57
tests/baselines/reference/controlFlowPrivateClassField.types
Normal file
57
tests/baselines/reference/controlFlowPrivateClassField.types
Normal file
@@ -0,0 +1,57 @@
|
||||
=== tests/cases/compiler/controlFlowPrivateClassField.ts ===
|
||||
class Example {
|
||||
>Example : Example
|
||||
|
||||
#test;
|
||||
>#test : number
|
||||
|
||||
constructor(test: number) {
|
||||
>test : number
|
||||
|
||||
this.#test = test;
|
||||
>this.#test = test : number
|
||||
>this.#test : number
|
||||
>this : this
|
||||
>test : number
|
||||
}
|
||||
|
||||
get test() {
|
||||
>test : number
|
||||
|
||||
return this.#test
|
||||
>this.#test : number
|
||||
>this : this
|
||||
}
|
||||
}
|
||||
|
||||
class Example2 {
|
||||
>Example2 : Example2
|
||||
|
||||
#test;
|
||||
>#test : number | undefined
|
||||
|
||||
constructor(test: number | undefined) {
|
||||
>test : number | undefined
|
||||
|
||||
this.#test = test;
|
||||
>this.#test = test : number | undefined
|
||||
>this.#test : number | undefined
|
||||
>this : this
|
||||
>test : number | undefined
|
||||
}
|
||||
|
||||
get test() {
|
||||
>test : number
|
||||
|
||||
if (this.#test) {
|
||||
>this.#test : number | undefined
|
||||
>this : this
|
||||
|
||||
return this.#test
|
||||
>this.#test : number
|
||||
>this : this
|
||||
}
|
||||
return 0;
|
||||
>0 : 0
|
||||
}
|
||||
}
|
||||
28
tests/cases/compiler/controlFlowPrivateClassField.ts
Normal file
28
tests/cases/compiler/controlFlowPrivateClassField.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
// @strict: true
|
||||
// @target: esnext
|
||||
class Example {
|
||||
#test;
|
||||
|
||||
constructor(test: number) {
|
||||
this.#test = test;
|
||||
}
|
||||
|
||||
get test() {
|
||||
return this.#test
|
||||
}
|
||||
}
|
||||
|
||||
class Example2 {
|
||||
#test;
|
||||
|
||||
constructor(test: number | undefined) {
|
||||
this.#test = test;
|
||||
}
|
||||
|
||||
get test() {
|
||||
if (this.#test) {
|
||||
return this.#test
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user