@@ -9158,7 +9158,8 @@ namespace ts {
9158
9158
getNodeLinks(accessNode!).resolvedSymbol = prop;
9159
9159
}
9160
9160
}
9161
- return getTypeOfSymbol(prop);
9161
+ const propType = getTypeOfSymbol(prop);
9162
+ return accessExpression ? getFlowTypeOfReference(accessExpression, propType) : propType;
9162
9163
}
9163
9164
if (isTupleType(objectType)) {
9164
9165
const restType = getRestTypeOfTupleType(objectType);
@@ -13778,9 +13779,10 @@ namespace ts {
13778
13779
case SyntaxKind.SuperKeyword:
13779
13780
return target.kind === SyntaxKind.SuperKeyword;
13780
13781
case SyntaxKind.PropertyAccessExpression:
13781
- return target.kind === SyntaxKind.PropertyAccessExpression &&
13782
- (<PropertyAccessExpression>source).name.escapedText === (<PropertyAccessExpression>target).name.escapedText &&
13783
- isMatchingReference((<PropertyAccessExpression>source).expression, (<PropertyAccessExpression>target).expression);
13782
+ case SyntaxKind.ElementAccessExpression:
13783
+ return (isPropertyAccessExpression(target) || isElementAccessExpression(target)) &&
13784
+ getAccessedPropertyName(source as PropertyAccessExpression | ElementAccessExpression) === getAccessedPropertyName(target) &&
13785
+ isMatchingReference((source as PropertyAccessExpression | ElementAccessExpression).expression, target.expression);
13784
13786
case SyntaxKind.BindingElement:
13785
13787
if (target.kind !== SyntaxKind.PropertyAccessExpression) return false;
13786
13788
const t = target as PropertyAccessExpression;
@@ -13796,6 +13798,12 @@ namespace ts {
13796
13798
return false;
13797
13799
}
13798
13800
13801
+ function getAccessedPropertyName(access: PropertyAccessExpression | ElementAccessExpression): __String | undefined {
13802
+ return isPropertyAccessExpression(access) ? access.name.escapedText :
13803
+ isStringLiteral(access.argumentExpression) || isNumericLiteral(access.argumentExpression) ? escapeLeadingUnderscores(access.argumentExpression.text) :
13804
+ undefined;
13805
+ }
13806
+
13799
13807
function containsMatchingReference(source: Node, target: Node) {
13800
13808
while (source.kind === SyntaxKind.PropertyAccessExpression) {
13801
13809
source = (<PropertyAccessExpression>source).expression;
@@ -14438,7 +14446,10 @@ namespace ts {
14438
14446
else if (flags & FlowFlags.Start) {
14439
14447
// Check if we should continue with the control flow of the containing function.
14440
14448
const container = (<FlowStart>flow).container;
14441
- if (container && container !== flowContainer && reference.kind !== SyntaxKind.PropertyAccessExpression && reference.kind !== SyntaxKind.ThisKeyword) {
14449
+ if (container && container !== flowContainer &&
14450
+ reference.kind !== SyntaxKind.PropertyAccessExpression &&
14451
+ reference.kind !== SyntaxKind.ElementAccessExpression &&
14452
+ reference.kind !== SyntaxKind.ThisKeyword) {
14442
14453
flow = container.flowNode!;
14443
14454
continue;
14444
14455
}
@@ -14555,7 +14566,10 @@ namespace ts {
14555
14566
type = narrowTypeBySwitchOnDiscriminant(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd);
14556
14567
}
14557
14568
else if (isMatchingReferenceDiscriminant(expr, type)) {
14558
- type = narrowTypeByDiscriminant(type, <PropertyAccessExpression>expr, t => narrowTypeBySwitchOnDiscriminant(t, flow.switchStatement, flow.clauseStart, flow.clauseEnd));
14569
+ type = narrowTypeByDiscriminant(
14570
+ type,
14571
+ expr as PropertyAccessExpression | ElementAccessExpression,
14572
+ t => narrowTypeBySwitchOnDiscriminant(t, flow.switchStatement, flow.clauseStart, flow.clauseEnd));
14559
14573
}
14560
14574
return createFlowType(type, isIncomplete(flowType));
14561
14575
}
@@ -14671,14 +14685,23 @@ namespace ts {
14671
14685
}
14672
14686
14673
14687
function isMatchingReferenceDiscriminant(expr: Expression, computedType: Type) {
14674
- return expr.kind === SyntaxKind.PropertyAccessExpression &&
14675
- computedType.flags & TypeFlags.Union &&
14676
- isMatchingReference(reference, (<PropertyAccessExpression>expr).expression) &&
14677
- isDiscriminantProperty(computedType, (<PropertyAccessExpression>expr).name.escapedText);
14688
+ if (!(computedType.flags & TypeFlags.Union) ||
14689
+ expr.kind !== SyntaxKind.PropertyAccessExpression && expr.kind !== SyntaxKind.ElementAccessExpression) {
14690
+ return false;
14691
+ }
14692
+ const access = expr as PropertyAccessExpression | ElementAccessExpression;
14693
+ const name = getAccessedPropertyName(access);
14694
+ if (!name) {
14695
+ return false;
14696
+ }
14697
+ return isMatchingReference(reference, access.expression) && isDiscriminantProperty(computedType, name);
14678
14698
}
14679
14699
14680
- function narrowTypeByDiscriminant(type: Type, propAccess: PropertyAccessExpression, narrowType: (t: Type) => Type): Type {
14681
- const propName = propAccess.name.escapedText;
14700
+ function narrowTypeByDiscriminant(type: Type, access: PropertyAccessExpression | ElementAccessExpression, narrowType: (t: Type) => Type): Type {
14701
+ const propName = getAccessedPropertyName(access);
14702
+ if (!propName) {
14703
+ return type;
14704
+ }
14682
14705
const propType = getTypeOfPropertyOfType(type, propName);
14683
14706
const narrowedPropType = propType && narrowType(propType);
14684
14707
return propType === narrowedPropType ? type : filterType(type, t => isTypeComparableTo(getTypeOfPropertyOfType(t, propName)!, narrowedPropType!));
@@ -14689,7 +14712,7 @@ namespace ts {
14689
14712
return getTypeWithFacts(type, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy);
14690
14713
}
14691
14714
if (isMatchingReferenceDiscriminant(expr, declaredType)) {
14692
- return narrowTypeByDiscriminant(type, <PropertyAccessExpression>expr, t => getTypeWithFacts(t, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy));
14715
+ return narrowTypeByDiscriminant(type, <PropertyAccessExpression | ElementAccessExpression >expr, t => getTypeWithFacts(t, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy));
14693
14716
}
14694
14717
if (containsMatchingReferenceDiscriminant(reference, expr)) {
14695
14718
return declaredType;
@@ -14740,10 +14763,10 @@ namespace ts {
14740
14763
return narrowTypeByEquality(type, operator, left, assumeTrue);
14741
14764
}
14742
14765
if (isMatchingReferenceDiscriminant(left, declaredType)) {
14743
- return narrowTypeByDiscriminant(type, <PropertyAccessExpression>left, t => narrowTypeByEquality(t, operator, right, assumeTrue));
14766
+ return narrowTypeByDiscriminant(type, <PropertyAccessExpression | ElementAccessExpression >left, t => narrowTypeByEquality(t, operator, right, assumeTrue));
14744
14767
}
14745
14768
if (isMatchingReferenceDiscriminant(right, declaredType)) {
14746
- return narrowTypeByDiscriminant(type, <PropertyAccessExpression>right, t => narrowTypeByEquality(t, operator, left, assumeTrue));
14769
+ return narrowTypeByDiscriminant(type, <PropertyAccessExpression | ElementAccessExpression >right, t => narrowTypeByEquality(t, operator, left, assumeTrue));
14747
14770
}
14748
14771
if (containsMatchingReferenceDiscriminant(reference, left) || containsMatchingReferenceDiscriminant(reference, right)) {
14749
14772
return declaredType;
@@ -14982,6 +15005,7 @@ namespace ts {
14982
15005
case SyntaxKind.ThisKeyword:
14983
15006
case SyntaxKind.SuperKeyword:
14984
15007
case SyntaxKind.PropertyAccessExpression:
15008
+ case SyntaxKind.ElementAccessExpression:
14985
15009
return narrowTypeByTruthiness(type, expr, assumeTrue);
14986
15010
case SyntaxKind.CallExpression:
14987
15011
return narrowTypeByTypePredicate(type, <CallExpression>expr, assumeTrue);
0 commit comments