Skip to content

Commit d61a693

Browse files
committed
More exploration of indexed access type constraints in type relations
1 parent 3e09d29 commit d61a693

File tree

1 file changed

+30
-25
lines changed

1 file changed

+30
-25
lines changed

src/compiler/checker.ts

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7488,15 +7488,18 @@ namespace ts {
74887488
}
74897489

74907490
function getConstraintFromIndexedAccess(type: IndexedAccessType) {
7491-
const objectType = getConstraintOfType(type.objectType) || type.objectType;
7492-
if (objectType !== type.objectType) {
7493-
const constraint = getIndexedAccessTypeOrUndefined(objectType, type.indexType);
7494-
if (constraint) {
7495-
return constraint;
7491+
const indexConstraint = getConstraintOfType(type.indexType);
7492+
if (indexConstraint && indexConstraint !== type.indexType) {
7493+
const indexedAccess = getIndexedAccessTypeOrUndefined(type.objectType, indexConstraint);
7494+
if (indexedAccess) {
7495+
return indexedAccess;
74967496
}
74977497
}
7498-
const baseConstraint = getBaseConstraintOfType(type);
7499-
return baseConstraint && baseConstraint !== type ? baseConstraint : undefined;
7498+
const objectConstraint = getConstraintOfType(type.objectType);
7499+
if (objectConstraint && objectConstraint !== type.objectType) {
7500+
return getIndexedAccessTypeOrUndefined(objectConstraint, type.indexType);
7501+
}
7502+
return undefined;
75007503
}
75017504

75027505
function getDefaultConstraintOfConditionalType(type: ConditionalType) {
@@ -9920,14 +9923,14 @@ namespace ts {
99209923
if (objectType.flags & (TypeFlags.Any | TypeFlags.Never)) {
99219924
return objectType;
99229925
}
9923-
const isAssignment = accessExpression && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression));
9924-
if (isAssignment && maybeTypeOfKind(originalObjectType, TypeFlags.Instantiable)) {
9925-
error(accessExpression, Diagnostics.Type_0_cannot_be_indexed_by_type_1, typeToString(originalObjectType), typeToString(indexType));
9926-
return undefined;
9927-
}
99289926
const indexInfo = isTypeAssignableToKind(indexType, TypeFlags.NumberLike) && getIndexInfoOfType(objectType, IndexKind.Number) ||
99299927
getIndexInfoOfType(objectType, IndexKind.String);
99309928
if (indexInfo) {
9929+
const isAssignment = accessExpression && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression));
9930+
if (isAssignment && maybeTypeOfKind(originalObjectType, TypeFlags.Instantiable)) {
9931+
error(accessExpression, Diagnostics.Type_0_cannot_be_indexed_by_type_1, typeToString(originalObjectType), typeToString(indexType));
9932+
return undefined;
9933+
}
99319934
if (accessNode && !isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) {
99329935
const indexNode = getIndexNodeForAccessExpression(accessNode);
99339936
error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType));
@@ -12820,7 +12823,7 @@ namespace ts {
1282012823
// A type S is related to a type T[K], where T and K aren't both type variables, if S is related to C,
1282112824
// where C is the base constraint of T[K]
1282212825
if (relation !== identityRelation) {
12823-
const objectType = (<IndexedAccessType>target).objectType
12826+
const objectType = (<IndexedAccessType>target).objectType;
1282412827
const indexType = (<IndexedAccessType>target).indexType;
1282512828
if (indexType.flags & TypeFlags.StructuredOrInstantiable) {
1282612829
const keyType = getLowerBoundOfKeyType(indexType, /*isIndexType*/ true);
@@ -12885,23 +12888,25 @@ namespace ts {
1288512888
return result;
1288612889
}
1288712890
}
12888-
const constraint = getConstraintOfType(<TypeVariable>source);
12889-
if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) {
12890-
// A type variable with no constraint is not related to the non-primitive object type.
12891-
if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
12891+
else {
12892+
const constraint = getConstraintOfType(<TypeVariable>source);
12893+
if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) {
12894+
// A type variable with no constraint is not related to the non-primitive object type.
12895+
if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
12896+
errorInfo = saveErrorInfo;
12897+
return result;
12898+
}
12899+
}
12900+
// hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed
12901+
else if (result = isRelatedTo(constraint, target, /*reportErrors*/ false, /*headMessage*/ undefined, isIntersectionConstituent)) {
1289212902
errorInfo = saveErrorInfo;
1289312903
return result;
1289412904
}
12895-
}
12896-
// hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed
12897-
else if (result = isRelatedTo(constraint, target, /*reportErrors*/ false, /*headMessage*/ undefined, isIntersectionConstituent)) {
12905+
// slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example
12906+
else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent)) {
1289812907
errorInfo = saveErrorInfo;
1289912908
return result;
12900-
}
12901-
// slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example
12902-
else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent)) {
12903-
errorInfo = saveErrorInfo;
12904-
return result;
12909+
}
1290512910
}
1290612911
}
1290712912
else if (source.flags & TypeFlags.Index) {

0 commit comments

Comments
 (0)