mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Narrowed consts flow through object literal or class expression method
Fixes #10501
This commit is contained in:
+11
-3
@@ -84,6 +84,7 @@ namespace ts {
|
||||
IsFunctionExpression = 1 << 4,
|
||||
HasLocals = 1 << 5,
|
||||
IsInterface = 1 << 6,
|
||||
IsObjectLiteralOrClassExpressionMethod = 1 << 7,
|
||||
}
|
||||
|
||||
const binder = createBinder();
|
||||
@@ -486,8 +487,8 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
currentFlow = { flags: FlowFlags.Start };
|
||||
if (containerFlags & ContainerFlags.IsFunctionExpression) {
|
||||
(<FlowStart>currentFlow).container = <FunctionExpression | ArrowFunction>node;
|
||||
if (containerFlags & (ContainerFlags.IsFunctionExpression | ContainerFlags.IsObjectLiteralOrClassExpressionMethod)) {
|
||||
(<FlowStart>currentFlow).container = <FunctionExpression | ArrowFunction | MethodDeclaration>node;
|
||||
}
|
||||
currentReturnTarget = undefined;
|
||||
}
|
||||
@@ -1237,9 +1238,12 @@ namespace ts {
|
||||
case SyntaxKind.SourceFile:
|
||||
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals;
|
||||
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
if (isObjectLiteralOrClassExpressionMethod(node)) {
|
||||
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsObjectLiteralOrClassExpressionMethod;
|
||||
}
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
@@ -2238,6 +2242,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
if (currentFlow && isObjectLiteralOrClassExpressionMethod(node)) {
|
||||
node.flowNode = currentFlow;
|
||||
}
|
||||
|
||||
return hasDynamicName(node)
|
||||
? bindAnonymousDeclaration(node, symbolFlags, "__computed")
|
||||
: declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
|
||||
|
||||
@@ -9163,7 +9163,9 @@ namespace ts {
|
||||
// a const variable or parameter from an outer function, we extend the origin of the control flow
|
||||
// analysis to include the immediately enclosing function.
|
||||
while (flowContainer !== declarationContainer &&
|
||||
(flowContainer.kind === SyntaxKind.FunctionExpression || flowContainer.kind === SyntaxKind.ArrowFunction) &&
|
||||
(flowContainer.kind === SyntaxKind.FunctionExpression ||
|
||||
flowContainer.kind === SyntaxKind.ArrowFunction ||
|
||||
isObjectLiteralOrClassExpressionMethod(flowContainer)) &&
|
||||
(isReadonlySymbol(localOrExportSymbol) || isParameter && !isParameterAssigned(localOrExportSymbol))) {
|
||||
flowContainer = getControlFlowContainer(flowContainer);
|
||||
}
|
||||
|
||||
@@ -1922,7 +1922,7 @@ namespace ts {
|
||||
// function, the container property references the function (which in turn has a flowNode
|
||||
// property for the containing control flow).
|
||||
export interface FlowStart extends FlowNode {
|
||||
container?: FunctionExpression | ArrowFunction;
|
||||
container?: FunctionExpression | ArrowFunction | MethodDeclaration;
|
||||
}
|
||||
|
||||
// FlowLabel represents a junction with multiple possible preceding control flows.
|
||||
|
||||
@@ -895,6 +895,12 @@ namespace ts {
|
||||
return node && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression;
|
||||
}
|
||||
|
||||
export function isObjectLiteralOrClassExpressionMethod(node: Node): node is MethodDeclaration {
|
||||
return node.kind === SyntaxKind.MethodDeclaration &&
|
||||
(node.parent.kind === SyntaxKind.ObjectLiteralExpression ||
|
||||
node.parent.kind === SyntaxKind.ClassExpression);
|
||||
}
|
||||
|
||||
export function isIdentifierTypePredicate(predicate: TypePredicate): predicate is IdentifierTypePredicate {
|
||||
return predicate && predicate.kind === TypePredicateKind.Identifier;
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
tests/cases/compiler/narrowedConstInMethod.ts(6,28): error TS2531: Object is possibly 'null'.
|
||||
tests/cases/compiler/narrowedConstInMethod.ts(15,28): error TS2531: Object is possibly 'null'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/narrowedConstInMethod.ts (2 errors) ====
|
||||
|
||||
function f() {
|
||||
const x: string | null = <any>{};
|
||||
if (x !== null) {
|
||||
return {
|
||||
bar() { return x.length; } // Error: possibly null x
|
||||
~
|
||||
!!! error TS2531: Object is possibly 'null'.
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function f2() {
|
||||
const x: string | null = <any>{};
|
||||
if (x !== null) {
|
||||
return class {
|
||||
bar() { return x.length; } // Error: possibly null x
|
||||
~
|
||||
!!! error TS2531: Object is possibly 'null'.
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
=== tests/cases/compiler/narrowedConstInMethod.ts ===
|
||||
|
||||
function f() {
|
||||
>f : Symbol(f, Decl(narrowedConstInMethod.ts, 0, 0))
|
||||
|
||||
const x: string | null = <any>{};
|
||||
>x : Symbol(x, Decl(narrowedConstInMethod.ts, 2, 9))
|
||||
|
||||
if (x !== null) {
|
||||
>x : Symbol(x, Decl(narrowedConstInMethod.ts, 2, 9))
|
||||
|
||||
return {
|
||||
bar() { return x.length; } // Error: possibly null x
|
||||
>bar : Symbol(bar, Decl(narrowedConstInMethod.ts, 4, 16))
|
||||
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(narrowedConstInMethod.ts, 2, 9))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function f2() {
|
||||
>f2 : Symbol(f2, Decl(narrowedConstInMethod.ts, 8, 1))
|
||||
|
||||
const x: string | null = <any>{};
|
||||
>x : Symbol(x, Decl(narrowedConstInMethod.ts, 11, 9))
|
||||
|
||||
if (x !== null) {
|
||||
>x : Symbol(x, Decl(narrowedConstInMethod.ts, 11, 9))
|
||||
|
||||
return class {
|
||||
bar() { return x.length; } // Error: possibly null x
|
||||
>bar : Symbol((Anonymous class).bar, Decl(narrowedConstInMethod.ts, 13, 22))
|
||||
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(narrowedConstInMethod.ts, 11, 9))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
=== tests/cases/compiler/narrowedConstInMethod.ts ===
|
||||
|
||||
function f() {
|
||||
>f : () => { bar(): number; } | undefined
|
||||
|
||||
const x: string | null = <any>{};
|
||||
>x : string | null
|
||||
>null : null
|
||||
><any>{} : any
|
||||
>{} : {}
|
||||
|
||||
if (x !== null) {
|
||||
>x !== null : boolean
|
||||
>x : string | null
|
||||
>null : null
|
||||
|
||||
return {
|
||||
>{ bar() { return x.length; } // Error: possibly null x } : { bar(): number; }
|
||||
|
||||
bar() { return x.length; } // Error: possibly null x
|
||||
>bar : () => number
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function f2() {
|
||||
>f2 : () => typeof (Anonymous class) | undefined
|
||||
|
||||
const x: string | null = <any>{};
|
||||
>x : string | null
|
||||
>null : null
|
||||
><any>{} : any
|
||||
>{} : {}
|
||||
|
||||
if (x !== null) {
|
||||
>x !== null : boolean
|
||||
>x : string | null
|
||||
>null : null
|
||||
|
||||
return class {
|
||||
>class { bar() { return x.length; } // Error: possibly null x } : typeof (Anonymous class)
|
||||
|
||||
bar() { return x.length; } // Error: possibly null x
|
||||
>bar : () => number
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user