@@ -7358,12 +7358,6 @@ namespace ts {
7358
7358
return flowTypeCaches[flow.id] || (flowTypeCaches[flow.id] = {});
7359
7359
}
7360
7360
7361
- function isNarrowableReference(expr: Node): boolean {
7362
- return expr.kind === SyntaxKind.Identifier ||
7363
- expr.kind === SyntaxKind.ThisKeyword ||
7364
- expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression);
7365
- }
7366
-
7367
7361
function typeMaybeAssignableTo(source: Type, target: Type) {
7368
7362
if (!(source.flags & TypeFlags.Union)) {
7369
7363
return isTypeAssignableTo(source, target);
@@ -7554,30 +7548,12 @@ namespace ts {
7554
7548
getInitialTypeOfBindingElement(<BindingElement>node);
7555
7549
}
7556
7550
7557
- function getNarrowedTypeOfReference(type: Type, reference: Node) {
7558
- if (!(type.flags & TypeFlags.Narrowable) || !isNarrowableReference(reference)) {
7559
- return type;
7560
- }
7561
- const leftmostNode = getLeftmostIdentifierOrThis(reference);
7562
- if (!leftmostNode) {
7563
- return type;
7564
- }
7565
- if (leftmostNode.kind === SyntaxKind.Identifier) {
7566
- const leftmostSymbol = getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(<Identifier>leftmostNode));
7567
- if (!leftmostSymbol) {
7568
- return type;
7569
- }
7570
- const declaration = leftmostSymbol.valueDeclaration;
7571
- if (!declaration || declaration.kind !== SyntaxKind.VariableDeclaration && declaration.kind !== SyntaxKind.Parameter && declaration.kind !== SyntaxKind.BindingElement) {
7572
- return type;
7573
- }
7574
- }
7575
- return getFlowTypeOfReference(reference, type, type);
7576
- }
7577
-
7578
7551
function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType: Type) {
7579
7552
let key: string;
7580
- return reference.flowNode ? getTypeAtFlowNode(reference.flowNode) : declaredType;
7553
+ if (!reference.flowNode || declaredType === initialType && !(declaredType.flags & TypeFlags.Narrowable)) {
7554
+ return declaredType;
7555
+ }
7556
+ return getTypeAtFlowNode(reference.flowNode);
7581
7557
7582
7558
function getTypeAtFlowNode(flow: FlowNode): Type {
7583
7559
while (true) {
@@ -7885,19 +7861,18 @@ namespace ts {
7885
7861
}
7886
7862
7887
7863
function getTypeOfSymbolAtLocation(symbol: Symbol, location: Node) {
7888
- // The language service will always care about the narrowed type of a symbol, because that is
7889
- // the type the language says the symbol should have.
7890
- const type = getTypeOfSymbol(symbol);
7864
+ // If we have an identifier or a property access at the given location, if the location is
7865
+ // an dotted name expression, and if the location is not an assignment target, obtain the type
7866
+ // of the expression (which will reflect control flow analysis). If the expression indeed
7867
+ // resolved to the given symbol, return the narrowed type.
7891
7868
if (location.kind === SyntaxKind.Identifier) {
7892
7869
if (isRightSideOfQualifiedNameOrPropertyAccess(location)) {
7893
7870
location = location.parent;
7894
7871
}
7895
- // If location is an identifier or property access that references the given
7896
- // symbol, use the location as the reference with respect to which we narrow.
7897
7872
if (isExpression(location) && !isAssignmentTarget(location)) {
7898
- checkExpression(<Expression>location);
7873
+ const type = checkExpression(<Expression>location);
7899
7874
if (getExportSymbolOfValueSymbolIfExported(getNodeLinks(location).resolvedSymbol) === symbol) {
7900
- return getNarrowedTypeOfReference( type, <IdentifierOrPropertyAccess>location) ;
7875
+ return type;
7901
7876
}
7902
7877
}
7903
7878
}
@@ -7906,7 +7881,7 @@ namespace ts {
7906
7881
// to it at the given location. Since we have no control flow information for the
7907
7882
// hypotherical reference (control flow information is created and attached by the
7908
7883
// binder), we simply return the declared type of the symbol.
7909
- return type ;
7884
+ return getTypeOfSymbol(symbol) ;
7910
7885
}
7911
7886
7912
7887
function skipParenthesizedNodes(expression: Expression): Expression {
@@ -7975,9 +7950,6 @@ namespace ts {
7975
7950
const defaultsToDeclaredType = !strictNullChecks || type.flags & TypeFlags.Any || !declaration ||
7976
7951
declaration.kind === SyntaxKind.Parameter || isInAmbientContext(declaration) ||
7977
7952
getContainingFunctionOrModule(declaration) !== getContainingFunctionOrModule(node);
7978
- if (defaultsToDeclaredType && !(type.flags & TypeFlags.Narrowable)) {
7979
- return type;
7980
- }
7981
7953
const flowType = getFlowTypeOfReference(node, type, defaultsToDeclaredType ? type : undefinedType);
7982
7954
if (strictNullChecks && !(type.flags & TypeFlags.Any) && !(getNullableKind(type) & TypeFlags.Undefined) && getNullableKind(flowType) & TypeFlags.Undefined) {
7983
7955
error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol));
@@ -8220,7 +8192,7 @@ namespace ts {
8220
8192
if (isClassLike(container.parent)) {
8221
8193
const symbol = getSymbolOfNode(container.parent);
8222
8194
const type = container.flags & NodeFlags.Static ? getTypeOfSymbol(symbol) : (<InterfaceType>getDeclaredTypeOfSymbol(symbol)).thisType;
8223
- return getNarrowedTypeOfReference( type, node );
8195
+ return getFlowTypeOfReference(node, type, type );
8224
8196
}
8225
8197
8226
8198
if (isInJavaScriptFile(node)) {
@@ -9784,8 +9756,24 @@ namespace ts {
9784
9756
}
9785
9757
9786
9758
const propType = getTypeOfSymbol(prop);
9787
- return node.kind === SyntaxKind.PropertyAccessExpression && prop.flags & (SymbolFlags.Variable | SymbolFlags.Property) && !isAssignmentTarget(node) ?
9788
- getNarrowedTypeOfReference(propType, <PropertyAccessExpression>node) : propType;
9759
+ if (node.kind !== SyntaxKind.PropertyAccessExpression || !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property)) || isAssignmentTarget(node)) {
9760
+ return propType;
9761
+ }
9762
+ const leftmostNode = getLeftmostIdentifierOrThis(node);
9763
+ if (!leftmostNode) {
9764
+ return propType;
9765
+ }
9766
+ if (leftmostNode.kind === SyntaxKind.Identifier) {
9767
+ const leftmostSymbol = getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(<Identifier>leftmostNode));
9768
+ if (!leftmostSymbol) {
9769
+ return propType;
9770
+ }
9771
+ const declaration = leftmostSymbol.valueDeclaration;
9772
+ if (!declaration || declaration.kind !== SyntaxKind.VariableDeclaration && declaration.kind !== SyntaxKind.Parameter && declaration.kind !== SyntaxKind.BindingElement) {
9773
+ return propType;
9774
+ }
9775
+ }
9776
+ return getFlowTypeOfReference(node, propType, propType);
9789
9777
}
9790
9778
9791
9779
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean {
0 commit comments