mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
More exploration of indexed access type constraints in type relations
This commit is contained in:
+30
-25
@@ -7488,15 +7488,18 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getConstraintFromIndexedAccess(type: IndexedAccessType) {
|
||||
const objectType = getConstraintOfType(type.objectType) || type.objectType;
|
||||
if (objectType !== type.objectType) {
|
||||
const constraint = getIndexedAccessTypeOrUndefined(objectType, type.indexType);
|
||||
if (constraint) {
|
||||
return constraint;
|
||||
const indexConstraint = getConstraintOfType(type.indexType);
|
||||
if (indexConstraint && indexConstraint !== type.indexType) {
|
||||
const indexedAccess = getIndexedAccessTypeOrUndefined(type.objectType, indexConstraint);
|
||||
if (indexedAccess) {
|
||||
return indexedAccess;
|
||||
}
|
||||
}
|
||||
const baseConstraint = getBaseConstraintOfType(type);
|
||||
return baseConstraint && baseConstraint !== type ? baseConstraint : undefined;
|
||||
const objectConstraint = getConstraintOfType(type.objectType);
|
||||
if (objectConstraint && objectConstraint !== type.objectType) {
|
||||
return getIndexedAccessTypeOrUndefined(objectConstraint, type.indexType);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getDefaultConstraintOfConditionalType(type: ConditionalType) {
|
||||
@@ -9920,14 +9923,14 @@ namespace ts {
|
||||
if (objectType.flags & (TypeFlags.Any | TypeFlags.Never)) {
|
||||
return objectType;
|
||||
}
|
||||
const isAssignment = accessExpression && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression));
|
||||
if (isAssignment && maybeTypeOfKind(originalObjectType, TypeFlags.Instantiable)) {
|
||||
error(accessExpression, Diagnostics.Type_0_cannot_be_indexed_by_type_1, typeToString(originalObjectType), typeToString(indexType));
|
||||
return undefined;
|
||||
}
|
||||
const indexInfo = isTypeAssignableToKind(indexType, TypeFlags.NumberLike) && getIndexInfoOfType(objectType, IndexKind.Number) ||
|
||||
getIndexInfoOfType(objectType, IndexKind.String);
|
||||
if (indexInfo) {
|
||||
const isAssignment = accessExpression && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression));
|
||||
if (isAssignment && maybeTypeOfKind(originalObjectType, TypeFlags.Instantiable)) {
|
||||
error(accessExpression, Diagnostics.Type_0_cannot_be_indexed_by_type_1, typeToString(originalObjectType), typeToString(indexType));
|
||||
return undefined;
|
||||
}
|
||||
if (accessNode && !isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) {
|
||||
const indexNode = getIndexNodeForAccessExpression(accessNode);
|
||||
error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType));
|
||||
@@ -12820,7 +12823,7 @@ namespace ts {
|
||||
// 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,
|
||||
// where C is the base constraint of T[K]
|
||||
if (relation !== identityRelation) {
|
||||
const objectType = (<IndexedAccessType>target).objectType
|
||||
const objectType = (<IndexedAccessType>target).objectType;
|
||||
const indexType = (<IndexedAccessType>target).indexType;
|
||||
if (indexType.flags & TypeFlags.StructuredOrInstantiable) {
|
||||
const keyType = getLowerBoundOfKeyType(indexType, /*isIndexType*/ true);
|
||||
@@ -12885,23 +12888,25 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
const constraint = getConstraintOfType(<TypeVariable>source);
|
||||
if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) {
|
||||
// A type variable with no constraint is not related to the non-primitive object type.
|
||||
if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
|
||||
else {
|
||||
const constraint = getConstraintOfType(<TypeVariable>source);
|
||||
if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) {
|
||||
// A type variable with no constraint is not related to the non-primitive object type.
|
||||
if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// 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
|
||||
else if (result = isRelatedTo(constraint, target, /*reportErrors*/ false, /*headMessage*/ undefined, isIntersectionConstituent)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// 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
|
||||
else if (result = isRelatedTo(constraint, target, /*reportErrors*/ false, /*headMessage*/ undefined, isIntersectionConstituent)) {
|
||||
// slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example
|
||||
else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
// slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example
|
||||
else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (source.flags & TypeFlags.Index) {
|
||||
|
||||
Reference in New Issue
Block a user