@@ -538,6 +538,7 @@ namespace ts {
538538
539539 const subtypeRelation = createMap<RelationComparisonResult>();
540540 const assignableRelation = createMap<RelationComparisonResult>();
541+ const definitelyAssignableRelation = createMap<RelationComparisonResult>();
541542 const comparableRelation = createMap<RelationComparisonResult>();
542543 const identityRelation = createMap<RelationComparisonResult>();
543544 const enumRelation = createMap<boolean>();
@@ -8128,8 +8129,11 @@ namespace ts {
81288129 }
81298130 // Instantiate the extends type including inferences for 'infer T' type parameters
81308131 const inferredExtendsType = combinedMapper ? instantiateType(baseExtendsType, combinedMapper) : extendsType;
8131- // Return trueType for a definitely true extends check
8132- if (isTypeAssignableTo(checkType, inferredExtendsType)) {
8132+ // Return trueType for a definitely true extends check. The definitely assignable relation excludes
8133+ // type variable constraints from consideration. Without the definitely assignable relation, the type
8134+ // type Foo<T extends { x: any }> = T extends { x: string } ? string : number
8135+ // would immediately resolve to 'string' instead of being deferred.
8136+ if (checkTypeRelatedTo(checkType, inferredExtendsType, definitelyAssignableRelation, /*errorNode*/ undefined)) {
81338137 return instantiateType(baseTrueType, combinedMapper || mapper);
81348138 }
81358139 // Return a deferred type for a check that is neither definitely true nor definitely false
@@ -9238,7 +9242,7 @@ namespace ts {
92389242 if (s & TypeFlags.Null && (!strictNullChecks || t & TypeFlags.Null)) return true;
92399243 if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive) return true;
92409244 if (s & TypeFlags.UniqueESSymbol || t & TypeFlags.UniqueESSymbol) return false;
9241- if (relation === assignableRelation || relation === comparableRelation) {
9245+ if (relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) {
92429246 if (s & TypeFlags.Any) return true;
92439247 // Type number or any numeric literal type is assignable to any numeric enum type or any
92449248 // numeric enum literal type. This rule exists for backwards compatibility reasons because
@@ -9407,7 +9411,7 @@ namespace ts {
94079411 target = (<LiteralType>target).regularType;
94089412 }
94099413 if (source.flags & TypeFlags.Substitution) {
9410- source = (<SubstitutionType>source).substitute;
9414+ source = relation === definitelyAssignableRelation ? (<SubstitutionType>source).typeParameter : (<SubstitutionType>source).substitute;
94119415 }
94129416 if (target.flags & TypeFlags.Substitution) {
94139417 target = (<SubstitutionType>target).typeParameter;
@@ -9538,7 +9542,7 @@ namespace ts {
95389542 function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean {
95399543 if (maybeTypeOfKind(target, TypeFlags.Object) && !(getObjectFlags(target) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) {
95409544 const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
9541- if ((relation === assignableRelation || relation === comparableRelation) &&
9545+ if ((relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) &&
95429546 (isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) {
95439547 return false;
95449548 }
@@ -9810,6 +9814,10 @@ namespace ts {
98109814 return result;
98119815 }
98129816
9817+ function getConstraintForRelation(type: Type) {
9818+ return relation === definitelyAssignableRelation ? undefined : getConstraintOfType(type);
9819+ }
9820+
98139821 function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
98149822 let result: Ternary;
98159823 let originalErrorInfo: DiagnosticMessageChain;
@@ -9835,7 +9843,7 @@ namespace ts {
98359843 }
98369844 // A type S is assignable to keyof T if S is assignable to keyof C, where C is the
98379845 // constraint of T.
9838- const constraint = getConstraintOfType ((<IndexType>target).type);
9846+ const constraint = getConstraintForRelation ((<IndexType>target).type);
98399847 if (constraint) {
98409848 if (result = isRelatedTo(source, getIndexType(constraint), reportErrors)) {
98419849 return result;
@@ -9845,7 +9853,7 @@ namespace ts {
98459853 else if (target.flags & TypeFlags.IndexedAccess) {
98469854 // A type S is related to a type T[K] if S is related to A[K], where K is string-like and
98479855 // A is the apparent type of T.
9848- const constraint = getConstraintOfIndexedAccess (<IndexedAccessType>target);
9856+ const constraint = getConstraintForRelation (<IndexedAccessType>target);
98499857 if (constraint) {
98509858 if (result = isRelatedTo(source, constraint, reportErrors)) {
98519859 errorInfo = saveErrorInfo;
@@ -9872,7 +9880,7 @@ namespace ts {
98729880 }
98739881
98749882 if (source.flags & TypeFlags.TypeParameter) {
9875- let constraint = getConstraintOfTypeParameter (<TypeParameter>source);
9883+ let constraint = getConstraintForRelation (<TypeParameter>source);
98769884 // A type parameter with no constraint is not related to the non-primitive object type.
98779885 if (constraint || !(target.flags & TypeFlags.NonPrimitive)) {
98789886 if (!constraint || constraint.flags & TypeFlags.Any) {
@@ -9889,7 +9897,7 @@ namespace ts {
98899897 else if (source.flags & TypeFlags.IndexedAccess) {
98909898 // A type S[K] is related to a type T if A[K] is related to T, where K is string-like and
98919899 // A is the apparent type of S.
9892- const constraint = getConstraintOfIndexedAccess (<IndexedAccessType>source);
9900+ const constraint = getConstraintForRelation (<IndexedAccessType>source);
98939901 if (constraint) {
98949902 if (result = isRelatedTo(constraint, target, reportErrors)) {
98959903 errorInfo = saveErrorInfo;
@@ -9906,11 +9914,13 @@ namespace ts {
99069914 }
99079915 }
99089916 else if (source.flags & TypeFlags.Conditional) {
9909- const constraint = getConstraintOfDistributiveConditionalType(<ConditionalType>source);
9910- if (constraint) {
9911- if (result = isRelatedTo(constraint, target, reportErrors)) {
9912- errorInfo = saveErrorInfo;
9913- return result;
9917+ if (relation !== definitelyAssignableRelation) {
9918+ const constraint = getConstraintOfDistributiveConditionalType(<ConditionalType>source);
9919+ if (constraint) {
9920+ if (result = isRelatedTo(constraint, target, reportErrors)) {
9921+ errorInfo = saveErrorInfo;
9922+ return result;
9923+ }
99149924 }
99159925 }
99169926 if (result = isRelatedTo(getDefaultConstraintOfConditionalType(<ConditionalType>source), target, reportErrors)) {
0 commit comments