@@ -6941,74 +6941,71 @@ namespace ts {
6941
6941
// Get the narrowed type of a given symbol at a given location
6942
6942
function getNarrowedTypeOfSymbol(symbol: Symbol, node: Node) {
6943
6943
let type = getTypeOfSymbol(symbol);
6944
- // Only narrow when symbol is variable of type any or an object, union, or type parameter type
6945
6944
if (node && symbol.flags & SymbolFlags.Variable) {
6946
- if (isTypeAny(type) || type.flags & (TypeFlags.ObjectType | TypeFlags.Union | TypeFlags.TypeParameter)) {
6947
- const declaration = getDeclarationOfKind(symbol, SyntaxKind.VariableDeclaration);
6948
- const top = declaration && getDeclarationContainer(declaration);
6949
- const originalType = type;
6950
- const nodeStack: {node: Node, child: Node}[] = [];
6951
- loop: while (node.parent) {
6952
- const child = node;
6953
- node = node.parent;
6954
- switch (node.kind) {
6955
- case SyntaxKind.IfStatement:
6956
- case SyntaxKind.ConditionalExpression:
6957
- case SyntaxKind.BinaryExpression:
6958
- nodeStack.push({node, child});
6959
- break;
6960
- case SyntaxKind.SourceFile:
6961
- case SyntaxKind.ModuleDeclaration:
6962
- // Stop at the first containing file or module declaration
6963
- break loop;
6964
- }
6965
- if (node === top) {
6945
+ const declaration = getDeclarationOfKind(symbol, SyntaxKind.VariableDeclaration);
6946
+ const top = declaration && getDeclarationContainer(declaration);
6947
+ const originalType = type;
6948
+ const nodeStack: {node: Node, child: Node}[] = [];
6949
+ loop: while (node.parent) {
6950
+ const child = node;
6951
+ node = node.parent;
6952
+ switch (node.kind) {
6953
+ case SyntaxKind.IfStatement:
6954
+ case SyntaxKind.ConditionalExpression:
6955
+ case SyntaxKind.BinaryExpression:
6956
+ nodeStack.push({node, child});
6966
6957
break;
6967
- }
6958
+ case SyntaxKind.SourceFile:
6959
+ case SyntaxKind.ModuleDeclaration:
6960
+ // Stop at the first containing file or module declaration
6961
+ break loop;
6962
+ }
6963
+ if (node === top) {
6964
+ break;
6968
6965
}
6966
+ }
6969
6967
6970
- let nodes: {node: Node, child: Node};
6971
- while (nodes = nodeStack.pop()) {
6972
- const {node, child} = nodes;
6973
- switch (node.kind) {
6974
- case SyntaxKind.IfStatement:
6975
- // In a branch of an if statement, narrow based on controlling expression
6976
- if (child !== (<IfStatement>node).expression) {
6977
- type = narrowType(type, (<IfStatement>node).expression, /*assumeTrue*/ child === (<IfStatement>node).thenStatement);
6978
- }
6979
- break;
6980
- case SyntaxKind.ConditionalExpression:
6981
- // In a branch of a conditional expression, narrow based on controlling condition
6982
- if (child !== (<ConditionalExpression>node).condition) {
6983
- type = narrowType(type, (<ConditionalExpression>node).condition, /*assumeTrue*/ child === (<ConditionalExpression>node).whenTrue);
6968
+ let nodes: {node: Node, child: Node};
6969
+ while (nodes = nodeStack.pop()) {
6970
+ const {node, child} = nodes;
6971
+ switch (node.kind) {
6972
+ case SyntaxKind.IfStatement:
6973
+ // In a branch of an if statement, narrow based on controlling expression
6974
+ if (child !== (<IfStatement>node).expression) {
6975
+ type = narrowType(type, (<IfStatement>node).expression, /*assumeTrue*/ child === (<IfStatement>node).thenStatement);
6976
+ }
6977
+ break;
6978
+ case SyntaxKind.ConditionalExpression:
6979
+ // In a branch of a conditional expression, narrow based on controlling condition
6980
+ if (child !== (<ConditionalExpression>node).condition) {
6981
+ type = narrowType(type, (<ConditionalExpression>node).condition, /*assumeTrue*/ child === (<ConditionalExpression>node).whenTrue);
6982
+ }
6983
+ break;
6984
+ case SyntaxKind.BinaryExpression:
6985
+ // In the right operand of an && or ||, narrow based on left operand
6986
+ if (child === (<BinaryExpression>node).right) {
6987
+ if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
6988
+ type = narrowType(type, (<BinaryExpression>node).left, /*assumeTrue*/ true);
6984
6989
}
6985
- break;
6986
- case SyntaxKind.BinaryExpression:
6987
- // In the right operand of an && or ||, narrow based on left operand
6988
- if (child === (<BinaryExpression>node).right) {
6989
- if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
6990
- type = narrowType(type, (<BinaryExpression>node).left, /*assumeTrue*/ true);
6991
- }
6992
- else if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken) {
6993
- type = narrowType(type, (<BinaryExpression>node).left, /*assumeTrue*/ false);
6994
- }
6990
+ else if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken) {
6991
+ type = narrowType(type, (<BinaryExpression>node).left, /*assumeTrue*/ false);
6995
6992
}
6996
- break;
6997
- default:
6998
- Debug.fail("Unreachable!");
6999
- }
7000
-
7001
- // Use original type if construct contains assignments to variable
7002
- if (type !== originalType && isVariableAssignedWithin(symbol, node)) {
7003
- type = originalType;
7004
- }
6993
+ }
6994
+ break;
6995
+ default:
6996
+ Debug.fail("Unreachable!");
7005
6997
}
7006
6998
7007
- // Preserve old top-level behavior - if the branch is really an empty set, revert to prior type
7008
- if (type === emptyUnionType ) {
6999
+ // Use original type if construct contains assignments to variable
7000
+ if (type !== originalType && isVariableAssignedWithin(symbol, node) ) {
7009
7001
type = originalType;
7010
7002
}
7011
7003
}
7004
+
7005
+ // Preserve old top-level behavior - if the branch is really an empty set, revert to prior type
7006
+ if (type === emptyUnionType) {
7007
+ type = originalType;
7008
+ }
7012
7009
}
7013
7010
7014
7011
return type;
0 commit comments