mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-20 05:17:43 -05:00
Fix type parameter comparability to consistently allow comparisons on unconstrained type parameters (#48861)
* Fix type parameter comparability to consistently allow comparisons on unconstrained type parameters * Less elaboration, non-strict-mode fix
This commit is contained in:
@@ -19347,6 +19347,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (relation === comparableRelation && sourceFlags & TypeFlags.TypeParameter) {
|
||||
// This is a carve-out in comparability to essentially forbid comparing a type parameter
|
||||
// with another type parameter unless one extends the other. (Remember: comparability is mostly bidirectional!)
|
||||
let constraint = getConstraintOfTypeParameter(source);
|
||||
if (constraint && hasNonCircularBaseConstraint(source)) {
|
||||
while (constraint && constraint.flags & TypeFlags.TypeParameter) {
|
||||
if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false)) {
|
||||
return result;
|
||||
}
|
||||
constraint = getConstraintOfTypeParameter(constraint);
|
||||
}
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
else if (targetFlags & TypeFlags.Index) {
|
||||
const targetType = (target as IndexType).type;
|
||||
@@ -19558,8 +19572,8 @@ namespace ts {
|
||||
if (sourceFlags & TypeFlags.TypeVariable) {
|
||||
// IndexedAccess comparisons are handled above in the `targetFlags & TypeFlage.IndexedAccess` branch
|
||||
if (!(sourceFlags & TypeFlags.IndexedAccess && targetFlags & TypeFlags.IndexedAccess)) {
|
||||
const constraint = getConstraintOfType(source as TypeVariable);
|
||||
if (!constraint || (sourceFlags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) {
|
||||
const constraint = getConstraintOfType(source as TypeVariable) || unknownType;
|
||||
if (!getConstraintOfType(source as TypeVariable) || (sourceFlags & 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), RecursionFlags.Both)) {
|
||||
resetErrorInfo(saveErrorInfo);
|
||||
@@ -19567,12 +19581,12 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
// 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, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) {
|
||||
if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) {
|
||||
resetErrorInfo(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, RecursionFlags.Source, reportErrors && !(targetFlags & sourceFlags & TypeFlags.TypeParameter), /*headMessage*/ undefined, intersectionState)) {
|
||||
else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, RecursionFlags.Source, reportErrors && constraint !== unknownType && !(targetFlags & sourceFlags & TypeFlags.TypeParameter), /*headMessage*/ undefined, intersectionState)) {
|
||||
resetErrorInfo(saveErrorInfo);
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user