diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 389881f1b5e..82c70861101 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5417,55 +5417,58 @@ module ts { function getNarrowedTypeOfSymbol(symbol: Symbol, node: Node) { let type = getTypeOfSymbol(symbol); // Only narrow when symbol is variable of type any or an object, union, or type parameter type - if (node && symbol.flags & SymbolFlags.Variable && type.flags & (TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.Union | TypeFlags.TypeParameter)) { - loop: while (node.parent) { - let child = node; - node = node.parent; - let narrowedType = type; - switch (node.kind) { - case SyntaxKind.IfStatement: - // In a branch of an if statement, narrow based on controlling expression - if (child !== (node).expression) { - narrowedType = narrowType(type, (node).expression, /*assumeTrue*/ child === (node).thenStatement); - } - break; - case SyntaxKind.ConditionalExpression: - // In a branch of a conditional expression, narrow based on controlling condition - if (child !== (node).condition) { - narrowedType = narrowType(type, (node).condition, /*assumeTrue*/ child === (node).whenTrue); - } - break; - case SyntaxKind.BinaryExpression: - // In the right operand of an && or ||, narrow based on left operand - if (child === (node).right) { - if ((node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { - narrowedType = narrowType(type, (node).left, /*assumeTrue*/ true); + if (node && symbol.flags & SymbolFlags.Variable) { + if (isTypeAny(type) || type.flags & (TypeFlags.ObjectType | TypeFlags.Union | TypeFlags.TypeParameter)) { + loop: while (node.parent) { + let child = node; + node = node.parent; + let narrowedType = type; + switch (node.kind) { + case SyntaxKind.IfStatement: + // In a branch of an if statement, narrow based on controlling expression + if (child !== (node).expression) { + narrowedType = narrowType(type, (node).expression, /*assumeTrue*/ child === (node).thenStatement); } - else if ((node).operatorToken.kind === SyntaxKind.BarBarToken) { - narrowedType = narrowType(type, (node).left, /*assumeTrue*/ false); + break; + case SyntaxKind.ConditionalExpression: + // In a branch of a conditional expression, narrow based on controlling condition + if (child !== (node).condition) { + narrowedType = narrowType(type, (node).condition, /*assumeTrue*/ child === (node).whenTrue); } - } - break; - case SyntaxKind.SourceFile: - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.Constructor: - // Stop at the first containing function or module declaration - break loop; - } - // Use narrowed type if construct contains no assignments to variable - if (narrowedType !== type) { - if (isVariableAssignedWithin(symbol, node)) { - break; + break; + case SyntaxKind.BinaryExpression: + // In the right operand of an && or ||, narrow based on left operand + if (child === (node).right) { + if ((node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { + narrowedType = narrowType(type, (node).left, /*assumeTrue*/ true); + } + else if ((node).operatorToken.kind === SyntaxKind.BarBarToken) { + narrowedType = narrowType(type, (node).left, /*assumeTrue*/ false); + } + } + break; + case SyntaxKind.SourceFile: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.Constructor: + // Stop at the first containing function or module declaration + break loop; + } + // Use narrowed type if construct contains no assignments to variable + if (narrowedType !== type) { + if (isVariableAssignedWithin(symbol, node)) { + break; + } + type = narrowedType; } - type = narrowedType; } } } + return type; function narrowTypeByEquality(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {