@@ -15315,13 +15315,6 @@ namespace ts {
15315
15315
return type[cache] = type;
15316
15316
}
15317
15317
15318
- function isConditionalTypeAlwaysTrueDisregardingInferTypes(type: ConditionalType) {
15319
- const extendsInferParamMapper = type.root.inferTypeParameters && createTypeMapper(type.root.inferTypeParameters, map(type.root.inferTypeParameters, () => wildcardType));
15320
- const checkType = type.checkType;
15321
- const extendsType = type.extendsType;
15322
- return isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(instantiateType(extendsType, extendsInferParamMapper)));
15323
- }
15324
-
15325
15318
function getSimplifiedConditionalType(type: ConditionalType, writing: boolean) {
15326
15319
const checkType = type.checkType;
15327
15320
const extendsType = type.extendsType;
@@ -15649,6 +15642,10 @@ namespace ts {
15649
15642
const links = getNodeLinks(node);
15650
15643
if (!links.resolvedType) {
15651
15644
const checkType = getTypeFromTypeNode(node.checkType);
15645
+ const isDistributive = !!(checkType.flags & TypeFlags.TypeParameter);
15646
+ const isDistributionDependent = isDistributive && (
15647
+ isTypeParameterPossiblyReferenced(checkType as TypeParameter, node.trueType) ||
15648
+ isTypeParameterPossiblyReferenced(checkType as TypeParameter, node.falseType));
15652
15649
const aliasSymbol = getAliasSymbolForTypeNode(node);
15653
15650
const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol);
15654
15651
const allOuterTypeParameters = getOuterTypeParameters(node, /*includeThisTypes*/ true);
@@ -15657,7 +15654,8 @@ namespace ts {
15657
15654
node,
15658
15655
checkType,
15659
15656
extendsType: getTypeFromTypeNode(node.extendsType),
15660
- isDistributive: !!(checkType.flags & TypeFlags.TypeParameter),
15657
+ isDistributive,
15658
+ isDistributionDependent,
15661
15659
inferTypeParameters: getInferTypeParameters(node),
15662
15660
outerTypeParameters,
15663
15661
instantiations: undefined,
@@ -19031,33 +19029,21 @@ namespace ts {
19031
19029
return Ternary.Maybe;
19032
19030
}
19033
19031
const c = target as ConditionalType;
19034
- // Check if the conditional is always true or always false but still deferred for distribution purposes
19035
- const skipTrue = !isTypeAssignableTo(getPermissiveInstantiation(c.checkType), getPermissiveInstantiation(c.extendsType));
19036
- const skipFalse = !skipTrue && isConditionalTypeAlwaysTrueDisregardingInferTypes(c);
19037
-
19038
- // Instantiate with a replacement mapper if the conditional is distributive, replacing the check type with a clone of itself,
19039
- // this way {x: string | number, y: string | number} -> (T extends T ? { x: T, y: T } : never) appropriately _fails_ when
19040
- // T = string | number (since that will end up distributing and producing `{x: string, y: string} | {x: number, y: number}`,
19041
- // to which `{x: string | number, y: string | number}` isn't assignable)
19042
- let distributionMapper: TypeMapper | undefined;
19043
- const checkVar = getActualTypeVariable(c.root.checkType);
19044
- if (c.root.isDistributive && checkVar.flags & TypeFlags.TypeParameter) {
19045
- const newParam = cloneTypeParameter(checkVar);
19046
- distributionMapper = prependTypeMapping(checkVar, newParam, c.mapper);
19047
- newParam.mapper = distributionMapper;
19048
- }
19049
-
19050
- // TODO: Find a nice way to include potential conditional type breakdowns in error output, if they seem good (they usually don't)
19051
- const expanding = isDeeplyNestedType(target, targetStack, targetDepth);
19052
- let localResult: Ternary | undefined = expanding ? Ternary.Maybe : undefined;
19053
- if (skipTrue || expanding || (localResult = isRelatedTo(source, distributionMapper ? instantiateType(getTypeFromTypeNode(c.root.node.trueType), distributionMapper) : getTrueTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false))) {
19054
- if (!skipFalse && !expanding) {
19055
- localResult = (localResult || Ternary.Maybe) & isRelatedTo(source, distributionMapper ? instantiateType(getTypeFromTypeNode(c.root.node.falseType), distributionMapper) : getFalseTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false);
19056
- }
19057
- }
19058
- if (localResult) {
19059
- resetErrorInfo(saveErrorInfo);
19060
- return localResult;
19032
+ // We check for a relationship to a conditional type target only when the conditional type has no
19033
+ // 'infer' positions and is not distributive or is distributive but doesn't reference the check type
19034
+ // parameter in either of the result types.
19035
+ if (!c.root.inferTypeParameters && !c.root.isDistributionDependent) {
19036
+ // Check if the conditional is always true or always false but still deferred for distribution purposes.
19037
+ const skipTrue = !isTypeAssignableTo(getPermissiveInstantiation(c.checkType), getPermissiveInstantiation(c.extendsType));
19038
+ const skipFalse = !skipTrue && isTypeAssignableTo(getRestrictiveInstantiation(c.checkType), getRestrictiveInstantiation(c.extendsType));
19039
+ // TODO: Find a nice way to include potential conditional type breakdowns in error output, if they seem good (they usually don't)
19040
+ if (result = skipTrue ? Ternary.True : isRelatedTo(source, getTrueTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false)) {
19041
+ result &= skipFalse ? Ternary.True : isRelatedTo(source, getFalseTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false);
19042
+ if (result) {
19043
+ resetErrorInfo(saveErrorInfo);
19044
+ return result;
19045
+ }
19046
+ }
19061
19047
}
19062
19048
}
19063
19049
else if (target.flags & TypeFlags.TemplateLiteral) {
0 commit comments