@@ -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 {
@@ -10441,11 +10441,13 @@ namespace ts {
10441
10441
// Return the flow cache key for a "dotted name" (i.e. a sequence of identifiers
10442
10442
// separated by dots). The key consists of the id of the symbol referenced by the
10443
10443
// leftmost identifier followed by zero or more property names separated by dots.
10444
- // The result is undefined if the reference isn't a dotted name.
10444
+ // The result is undefined if the reference isn't a dotted name. We prefix nodes
10445
+ // occurring in an apparent type position with '@' because the control flow type
10446
+ // of such nodes may be based on the apparent type instead of the declared type.
10445
10447
function getFlowCacheKey(node: Node): string {
10446
10448
if (node.kind === SyntaxKind.Identifier) {
10447
10449
const symbol = getResolvedSymbol(<Identifier>node);
10448
- return symbol !== unknownSymbol ? "" + getSymbolId(symbol) : undefined;
10450
+ return symbol !== unknownSymbol ? (isApparentTypePosition(node) ? "@" : "") + getSymbolId(symbol) : undefined;
10449
10451
}
10450
10452
if (node.kind === SyntaxKind.ThisKeyword) {
10451
10453
return "0";
@@ -11710,6 +11712,29 @@ namespace ts {
11710
11712
return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType;
11711
11713
}
11712
11714
11715
+ function isApparentTypePosition(node: Node) {
11716
+ const parent = node.parent;
11717
+ return parent.kind === SyntaxKind.PropertyAccessExpression ||
11718
+ parent.kind === SyntaxKind.CallExpression && (<CallExpression>parent).expression === node ||
11719
+ parent.kind === SyntaxKind.ElementAccessExpression && (<ElementAccessExpression>parent).expression === node;
11720
+ }
11721
+
11722
+ function typeHasNullableConstraint(type: Type) {
11723
+ return type.flags & TypeFlags.TypeVariable && maybeTypeOfKind(getBaseConstraintOfType(type) || emptyObjectType, TypeFlags.Nullable);
11724
+ }
11725
+
11726
+ function getDeclaredOrApparentType(symbol: Symbol, node: Node) {
11727
+ // When a node is the left hand expression of a property access, element access, or call expression,
11728
+ // and the type of the node includes type variables with constraints that are nullable, we fetch the
11729
+ // apparent type of the node *before* performing control flow analysis such that narrowings apply to
11730
+ // the constraint type.
11731
+ const type = getTypeOfSymbol(symbol);
11732
+ if (isApparentTypePosition(node) && forEachType(type, typeHasNullableConstraint)) {
11733
+ return mapType(getWidenedType(type), getApparentType);
11734
+ }
11735
+ return type;
11736
+ }
11737
+
11713
11738
function checkIdentifier(node: Identifier): Type {
11714
11739
const symbol = getResolvedSymbol(node);
11715
11740
if (symbol === unknownSymbol) {
@@ -11785,7 +11810,7 @@ namespace ts {
11785
11810
checkCollisionWithCapturedNewTargetVariable(node, node);
11786
11811
checkNestedBlockScopedBinding(node, symbol);
11787
11812
11788
- const type = getTypeOfSymbol (localOrExportSymbol);
11813
+ const type = getDeclaredOrApparentType (localOrExportSymbol, node );
11789
11814
const declaration = localOrExportSymbol.valueDeclaration;
11790
11815
const assignmentKind = getAssignmentTargetKind(node);
11791
11816
@@ -14158,7 +14183,7 @@ namespace ts {
14158
14183
14159
14184
checkPropertyAccessibility(node, left, apparentType, prop);
14160
14185
14161
- const propType = getTypeOfSymbol (prop);
14186
+ const propType = getDeclaredOrApparentType (prop, node );
14162
14187
const assignmentKind = getAssignmentTargetKind(node);
14163
14188
14164
14189
if (assignmentKind) {
0 commit comments