@@ -4015,7 +4015,7 @@ namespace ts {
4015
4015
parentType = getNonNullableType(parentType);
4016
4016
}
4017
4017
const propType = getTypeOfPropertyOfType(parentType, text);
4018
- const declaredType = propType && getApparentTypeForLocation (propType, declaration.name);
4018
+ const declaredType = propType && getConstraintForLocation (propType, declaration.name);
4019
4019
type = declaredType && getFlowTypeOfReference(declaration, declaredType) ||
4020
4020
isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
4021
4021
getIndexTypeOfType(parentType, IndexKind.String);
@@ -6138,17 +6138,29 @@ namespace ts {
6138
6138
return getConstraintOfDistributiveConditionalType(type) || getDefaultConstraintOfConditionalType(type);
6139
6139
}
6140
6140
6141
- function getBaseConstraintOfType (type: Type): Type {
6141
+ function getBaseConstraintOfInstantiableNonPrimitiveUnionOrIntersection (type: Type) {
6142
6142
if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection)) {
6143
6143
const constraint = getResolvedBaseConstraint(<InstantiableType | UnionOrIntersectionType>type);
6144
6144
if (constraint !== noConstraintType && constraint !== circularConstraintType) {
6145
6145
return constraint;
6146
6146
}
6147
6147
}
6148
- else if (type.flags & TypeFlags.Index) {
6148
+ }
6149
+
6150
+ function getBaseConstraintOfType(type: Type): Type {
6151
+ const constraint = getBaseConstraintOfInstantiableNonPrimitiveUnionOrIntersection(type);
6152
+ if (!constraint && type.flags & TypeFlags.Index) {
6149
6153
return stringType;
6150
6154
}
6151
- return undefined;
6155
+ return constraint;
6156
+ }
6157
+
6158
+ /**
6159
+ * This is similar to `getBaseConstraintOfType` except it returns the input type if there's no base constraint, instead of `undefined`
6160
+ * It also doesn't map indexes to `string`, as where this is used this would be unneeded (and likely undesirable)
6161
+ */
6162
+ function getBaseConstraintOrType(type: Type) {
6163
+ return getBaseConstraintOfType(type) || type;
6152
6164
}
6153
6165
6154
6166
function hasNonCircularBaseConstraint(type: InstantiableType): boolean {
@@ -11935,7 +11947,7 @@ namespace ts {
11935
11947
function getFlowCacheKey(node: Node): string | undefined {
11936
11948
if (node.kind === SyntaxKind.Identifier) {
11937
11949
const symbol = getResolvedSymbol(<Identifier>node);
11938
- return symbol !== unknownSymbol ? (isApparentTypePosition (node) ? "@" : "") + getSymbolId(symbol) : undefined;
11950
+ return symbol !== unknownSymbol ? (isConstraintPosition (node) ? "@" : "") + getSymbolId(symbol) : undefined;
11939
11951
}
11940
11952
if (node.kind === SyntaxKind.ThisKeyword) {
11941
11953
return "0";
@@ -13297,7 +13309,7 @@ namespace ts {
13297
13309
return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType;
13298
13310
}
13299
13311
13300
- function isApparentTypePosition (node: Node) {
13312
+ function isConstraintPosition (node: Node) {
13301
13313
const parent = node.parent;
13302
13314
return parent.kind === SyntaxKind.PropertyAccessExpression ||
13303
13315
parent.kind === SyntaxKind.CallExpression && (<CallExpression>parent).expression === node ||
@@ -13310,13 +13322,13 @@ namespace ts {
13310
13322
return type.flags & TypeFlags.InstantiableNonPrimitive && maybeTypeOfKind(getBaseConstraintOfType(type) || emptyObjectType, TypeFlags.Nullable);
13311
13323
}
13312
13324
13313
- function getApparentTypeForLocation (type: Type, node: Node) {
13325
+ function getConstraintForLocation (type: Type, node: Node) {
13314
13326
// When a node is the left hand expression of a property access, element access, or call expression,
13315
13327
// and the type of the node includes type variables with constraints that are nullable, we fetch the
13316
13328
// apparent type of the node *before* performing control flow analysis such that narrowings apply to
13317
13329
// the constraint type.
13318
- if (isApparentTypePosition (node) && forEachType(type, typeHasNullableConstraint)) {
13319
- return mapType(getWidenedType(type), getApparentType );
13330
+ if (isConstraintPosition (node) && forEachType(type, typeHasNullableConstraint)) {
13331
+ return mapType(getWidenedType(type), getBaseConstraintOrType );
13320
13332
}
13321
13333
return type;
13322
13334
}
@@ -13404,7 +13416,7 @@ namespace ts {
13404
13416
checkCollisionWithCapturedNewTargetVariable(node, node);
13405
13417
checkNestedBlockScopedBinding(node, symbol);
13406
13418
13407
- const type = getApparentTypeForLocation (getTypeOfSymbol(localOrExportSymbol), node);
13419
+ const type = getConstraintForLocation (getTypeOfSymbol(localOrExportSymbol), node);
13408
13420
const assignmentKind = getAssignmentTargetKind(node);
13409
13421
13410
13422
if (assignmentKind) {
@@ -16024,7 +16036,7 @@ namespace ts {
16024
16036
return unknownType;
16025
16037
}
16026
16038
}
16027
- propType = getApparentTypeForLocation (getTypeOfSymbol(prop), node);
16039
+ propType = getConstraintForLocation (getTypeOfSymbol(prop), node);
16028
16040
}
16029
16041
// Only compute control flow type if this is a property access expression that isn't an
16030
16042
// assignment target, and the referenced property was declared as a variable, property,
0 commit comments