@@ -25338,13 +25338,24 @@ namespace ts {
25338
25338
// control flow analysis an opportunity to narrow it further. For example, for a reference of a type
25339
25339
// parameter type 'T extends string | undefined' with a contextual type 'string', we substitute
25340
25340
// 'string | undefined' to give control flow analysis the opportunity to narrow to type 'string'.
25341
+ if (checkMode && checkMode & CheckMode.Inferential) {
25342
+ return type;
25343
+ }
25344
+
25341
25345
let contextualType: Type | undefined;
25342
- const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) &&
25343
- (isConstraintPosition(type, reference) || (contextualType = tryGetContextualTypeWithNoGenericTypes(reference, checkMode))) &&
25344
- (
25345
- someType(type, isGenericTypeWithUnionConstraint) ||
25346
- ((type.flags & TypeFlags.Instantiable) && contextualType && isEmptyObjectType(contextualType))
25347
- );
25346
+ // If we aren't in a constraint position, or we can't find a contextual type, or the contextual type indicates
25347
+ // that the type in question may be a direct inference source, then don't do anything special.
25348
+ if (!isConstraintPosition(type, reference) && !(contextualType = tryGetContextualTypeWithNoGenericTypes(reference, checkMode))) {
25349
+ return type;
25350
+ }
25351
+
25352
+ const substituteConstraints =
25353
+ // When we have a type parameter constrained to a union type, we can typically narrow to get better results.
25354
+ someType(type, isGenericTypeWithUnionConstraint) ||
25355
+ // When the contextual type is 'unknown', we may need to narrow for compatibility with non-null targets.
25356
+ // This allows some parity with a constraint of '{} | null | undefined'.
25357
+ (type.flags & TypeFlags.Instantiable) && contextualType && isEmptyObjectType(contextualType);
25358
+
25348
25359
return substituteConstraints ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(t) || unknownType : t) : type;
25349
25360
}
25350
25361
0 commit comments