@@ -7358,12 +7358,6 @@ namespace ts {
73587358 return flowTypeCaches[flow.id] || (flowTypeCaches[flow.id] = {});
73597359 }
73607360
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-
73677361 function typeMaybeAssignableTo(source: Type, target: Type) {
73687362 if (!(source.flags & TypeFlags.Union)) {
73697363 return isTypeAssignableTo(source, target);
@@ -7554,30 +7548,12 @@ namespace ts {
75547548 getInitialTypeOfBindingElement(<BindingElement>node);
75557549 }
75567550
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-
75787551 function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType: Type) {
75797552 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);
75817557
75827558 function getTypeAtFlowNode(flow: FlowNode): Type {
75837559 while (true) {
@@ -7885,19 +7861,18 @@ namespace ts {
78857861 }
78867862
78877863 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.
78917868 if (location.kind === SyntaxKind.Identifier) {
78927869 if (isRightSideOfQualifiedNameOrPropertyAccess(location)) {
78937870 location = location.parent;
78947871 }
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.
78977872 if (isExpression(location) && !isAssignmentTarget(location)) {
7898- checkExpression(<Expression>location);
7873+ const type = checkExpression(<Expression>location);
78997874 if (getExportSymbolOfValueSymbolIfExported(getNodeLinks(location).resolvedSymbol) === symbol) {
7900- return getNarrowedTypeOfReference( type, <IdentifierOrPropertyAccess>location) ;
7875+ return type;
79017876 }
79027877 }
79037878 }
@@ -7906,7 +7881,7 @@ namespace ts {
79067881 // to it at the given location. Since we have no control flow information for the
79077882 // hypotherical reference (control flow information is created and attached by the
79087883 // binder), we simply return the declared type of the symbol.
7909- return type ;
7884+ return getTypeOfSymbol(symbol) ;
79107885 }
79117886
79127887 function skipParenthesizedNodes(expression: Expression): Expression {
@@ -7975,9 +7950,6 @@ namespace ts {
79757950 const defaultsToDeclaredType = !strictNullChecks || type.flags & TypeFlags.Any || !declaration ||
79767951 declaration.kind === SyntaxKind.Parameter || isInAmbientContext(declaration) ||
79777952 getContainingFunctionOrModule(declaration) !== getContainingFunctionOrModule(node);
7978- if (defaultsToDeclaredType && !(type.flags & TypeFlags.Narrowable)) {
7979- return type;
7980- }
79817953 const flowType = getFlowTypeOfReference(node, type, defaultsToDeclaredType ? type : undefinedType);
79827954 if (strictNullChecks && !(type.flags & TypeFlags.Any) && !(getNullableKind(type) & TypeFlags.Undefined) && getNullableKind(flowType) & TypeFlags.Undefined) {
79837955 error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol));
@@ -8220,7 +8192,7 @@ namespace ts {
82208192 if (isClassLike(container.parent)) {
82218193 const symbol = getSymbolOfNode(container.parent);
82228194 const type = container.flags & NodeFlags.Static ? getTypeOfSymbol(symbol) : (<InterfaceType>getDeclaredTypeOfSymbol(symbol)).thisType;
8223- return getNarrowedTypeOfReference( type, node );
8195+ return getFlowTypeOfReference(node, type, type );
82248196 }
82258197
82268198 if (isInJavaScriptFile(node)) {
@@ -9784,8 +9756,24 @@ namespace ts {
97849756 }
97859757
97869758 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);
97899777 }
97909778
97919779 function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean {
0 commit comments