@@ -5775,11 +5775,11 @@ namespace ts {
5775
5775
const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : type;
5776
5776
return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(<IntersectionType>t) :
5777
5777
t.flags & TypeFlags.StringLike ? globalStringType :
5778
- t.flags & TypeFlags.NumberLike ? globalNumberType :
5779
- t.flags & TypeFlags.BooleanLike ? globalBooleanType :
5780
- t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType(/*reportErrors*/ languageVersion >= ScriptTarget.ES2015) :
5781
- t.flags & TypeFlags.NonPrimitive ? emptyObjectType :
5782
- t;
5778
+ t.flags & TypeFlags.NumberLike ? globalNumberType :
5779
+ t.flags & TypeFlags.BooleanLike ? globalBooleanType :
5780
+ t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType(/*reportErrors*/ languageVersion >= ScriptTarget.ES2015) :
5781
+ t.flags & TypeFlags.NonPrimitive ? emptyObjectType :
5782
+ t;
5783
5783
}
5784
5784
5785
5785
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string): Symbol {
@@ -10439,11 +10439,13 @@ namespace ts {
10439
10439
// Return the flow cache key for a "dotted name" (i.e. a sequence of identifiers
10440
10440
// separated by dots). The key consists of the id of the symbol referenced by the
10441
10441
// leftmost identifier followed by zero or more property names separated by dots.
10442
- // The result is undefined if the reference isn't a dotted name.
10442
+ // The result is undefined if the reference isn't a dotted name. We prefix nodes
10443
+ // occurring in an apparent type position with '@' because the control flow type
10444
+ // of such nodes may be based on the apparent type instead of the declared type.
10443
10445
function getFlowCacheKey(node: Node): string {
10444
10446
if (node.kind === SyntaxKind.Identifier) {
10445
10447
const symbol = getResolvedSymbol(<Identifier>node);
10446
- return symbol !== unknownSymbol ? "" + getSymbolId(symbol) : undefined;
10448
+ return symbol !== unknownSymbol ? (isApparentTypePosition(node) ? "@" : "") + getSymbolId(symbol) : undefined;
10447
10449
}
10448
10450
if (node.kind === SyntaxKind.ThisKeyword) {
10449
10451
return "0";
@@ -11708,6 +11710,28 @@ namespace ts {
11708
11710
return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType;
11709
11711
}
11710
11712
11713
+ function isApparentTypePosition(node: Node) {
11714
+ // When a node is the left hand expression of a property access or call expression, the node occurs
11715
+ // in an apparent type position. In such a position we fetch the apparent type of the node *before*
11716
+ // performing control flow analysis such that, if the node is a type variable, we apply narrowings
11717
+ // to the constraint type.
11718
+ const parent = node.parent;
11719
+ return parent.kind === SyntaxKind.PropertyAccessExpression ||
11720
+ parent.kind === SyntaxKind.CallExpression && (<CallExpression>parent).expression === node ||
11721
+ parent.kind === SyntaxKind.ElementAccessExpression && (<ElementAccessExpression>parent).expression === node;
11722
+ }
11723
+
11724
+ function getDeclaredOrApparentType(symbol: Symbol, node: Node) {
11725
+ const type = getTypeOfSymbol(symbol);
11726
+ if (isApparentTypePosition(node) && maybeTypeOfKind(type, TypeFlags.TypeVariable)) {
11727
+ const apparentType = mapType(getWidenedType(type), getApparentType);
11728
+ if (apparentType !== emptyObjectType) {
11729
+ return apparentType;
11730
+ }
11731
+ }
11732
+ return type;
11733
+ }
11734
+
11711
11735
function checkIdentifier(node: Identifier): Type {
11712
11736
const symbol = getResolvedSymbol(node);
11713
11737
if (symbol === unknownSymbol) {
@@ -11783,7 +11807,7 @@ namespace ts {
11783
11807
checkCollisionWithCapturedNewTargetVariable(node, node);
11784
11808
checkNestedBlockScopedBinding(node, symbol);
11785
11809
11786
- const type = getTypeOfSymbol (localOrExportSymbol);
11810
+ const type = getDeclaredOrApparentType (localOrExportSymbol, node );
11787
11811
const declaration = localOrExportSymbol.valueDeclaration;
11788
11812
const assignmentKind = getAssignmentTargetKind(node);
11789
11813
@@ -14141,7 +14165,7 @@ namespace ts {
14141
14165
14142
14166
checkPropertyAccessibility(node, left, apparentType, prop);
14143
14167
14144
- const propType = getTypeOfSymbol (prop);
14168
+ const propType = getDeclaredOrApparentType (prop, node );
14145
14169
const assignmentKind = getAssignmentTargetKind(node);
14146
14170
14147
14171
if (assignmentKind) {
0 commit comments