@@ -26441,18 +26441,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2644126441 const templateType = getTemplateTypeFromMappedType(target);
2644226442 const inference = createInferenceInfo(inferenceTarget);
2644326443 inferTypes([inference], sourceType, templateType);
26444- const inferredType = getTypeFromInference(inference);
26445- if (inferredType) {
26446- return inferredType;
26447- }
26448- if (inference.indexes) {
26449- const eraseSelfMapper = makeArrayTypeMapper([constraint.type, typeParameter], [allKeysAllKeysUnknownType, stringNumberSymbolType]);
26450- const aggregateInference = instantiateType(getIntersectionType(inference.indexes), eraseSelfMapper);
26451- if (!(getReducedType(aggregateInference).flags & TypeFlags.Never)) {
26452- return aggregateInference;
26453- }
26454- }
26455- return unknownType;
26444+ return getTypeFromInference(inference) || unknownType;
2645626445 }
2645726446
2645826447 function inferReverseMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {
@@ -26521,7 +26510,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2652126510 function getTypeFromInference(inference: InferenceInfo) {
2652226511 return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) :
2652326512 inference.contraCandidates ? getIntersectionType(inference.contraCandidates) :
26524- undefined ;
26513+ getAggregateInference(inference) ;
2652526514 }
2652626515
2652726516 function hasSkipDirectInferenceFlag(node: Node) {
@@ -27568,6 +27557,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2756827557 return getWidenedType(unwidenedType);
2756927558 }
2757027559
27560+ function getAggregateInference(inference: InferenceInfo, constraintType?: Type, compareTypes?: TypeComparer, mapper?: TypeMapper | undefined): Type | undefined {
27561+ if (!inference.indexes) {
27562+ return undefined;
27563+ }
27564+ const typeEraser = createTypeEraser([inference.typeParameter.flags & TypeFlags.IndexedAccess ? (inference.typeParameter as IndexedAccessType).objectType : inference.typeParameter]);
27565+ const aggregateInference = instantiateType(getIntersectionType(inference.indexes), mapper ? mergeTypeMappers(typeEraser, mapper) : typeEraser);
27566+ if (getReducedType(aggregateInference).flags & TypeFlags.Never) {
27567+ // `never` inference isn't that useful of an inference given its assignable to every other type
27568+ return undefined;
27569+ }
27570+ if (!constraintType || (compareTypes ??= compareTypesAssignable)(aggregateInference, getTypeWithThisArgument(constraintType, aggregateInference))) {
27571+ return aggregateInference;
27572+ }
27573+ if (constraintType.flags & TypeFlags.Union) {
27574+ const discriminantProps = findDiscriminantProperties(getPropertiesOfType(aggregateInference), constraintType);
27575+ if (discriminantProps) {
27576+ let match: Type | undefined;
27577+ findDiscriminant:
27578+ for (const p of discriminantProps) {
27579+ const candidatePropType = getTypeOfPropertyOfType(aggregateInference, p.escapedName);
27580+ for (const type of (constraintType as UnionType).types) {
27581+ const propType = getTypeOfPropertyOfType(type, p.escapedName);
27582+ if (propType && candidatePropType && isTypeAssignableTo(candidatePropType, propType)) {
27583+ if (match && match !== type) {
27584+ match = undefined;
27585+ break findDiscriminant;
27586+ }
27587+ else {
27588+ match = type;
27589+ }
27590+ }
27591+ }
27592+ }
27593+ if (match) {
27594+ const combinedType = getSpreadType(match, aggregateInference, /*symbol*/ undefined, /*propegatedFlags*/ 0, /*readonly*/ false);
27595+ if (compareTypes(combinedType, getTypeWithThisArgument(constraintType, combinedType))) {
27596+ return combinedType;
27597+ }
27598+ }
27599+ }
27600+ }
27601+ // if the aggregate inference isn't assignable to the constraint return undefined
27602+ // this way the compiler keeps preferring the default type
27603+ return undefined;
27604+ }
27605+
2757127606 function getInferredType(context: InferenceContext, index: number): Type {
2757227607 const inference = context.inferences[index];
2757327608 if (!inference.inferredType) {
@@ -27593,51 +27628,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2759327628 fallbackType = preferCovariantType ? inferredContravariantType : inferredCovariantType;
2759427629 }
2759527630 else if (inference.indexes) {
27596- const eraseSelfMapper = makeUnaryTypeMapper(inference.typeParameter, allKeysUnknownType);
27597- let aggregateInference: Type | undefined = instantiateType(getIntersectionType(inference.indexes), mergeTypeMappers(eraseSelfMapper, context.nonFixingMapper));
27598- if (getReducedType(aggregateInference).flags & TypeFlags.Never) {
27599- // `never` inference isn't that useful of an inference given its assignable to every other type
27600- aggregateInference = undefined;
27601- }
27602- const constraint = getConstraintOfTypeParameter(inference.typeParameter);
27603- if (aggregateInference && constraint) {
27604- const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper);
27605- let assignableToConstraint = context.compareTypes(aggregateInference, getTypeWithThisArgument(instantiatedConstraint, aggregateInference));
27606- if (!assignableToConstraint) {
27607- if (instantiatedConstraint.flags & TypeFlags.Union) {
27608- const discriminantProps = findDiscriminantProperties(getPropertiesOfType(aggregateInference), instantiatedConstraint);
27609- if (discriminantProps) {
27610- let match: Type | undefined;
27611- findDiscriminant:
27612- for (const p of discriminantProps) {
27613- const candidatePropType = getTypeOfPropertyOfType(aggregateInference, p.escapedName);
27614- for (const type of (instantiatedConstraint as UnionType).types) {
27615- const propType = getTypeOfPropertyOfType(type, p.escapedName);
27616- if (propType && candidatePropType && checkTypeAssignableTo(candidatePropType, propType, /*errorNode*/ undefined)) {
27617- if (match && match !== type) {
27618- match = undefined;
27619- break findDiscriminant;
27620- }
27621- else {
27622- match = type;
27623- }
27624- }
27625- }
27626- }
27627- if (match) {
27628- aggregateInference = getSpreadType(match, aggregateInference, /*symbol*/ undefined, /*propegatedFlags*/ 0, /*readonly*/ false);
27629- assignableToConstraint = context.compareTypes(aggregateInference, getTypeWithThisArgument(instantiatedConstraint, aggregateInference));
27630- }
27631- }
27632- }
27633- if (!assignableToConstraint) {
27634- // if the aggregate inference isn't assignable to the constraint clear it out
27635- // this way the compiler keeps preferring the default type
27636- aggregateInference = undefined;
27637- }
27638- }
27639- }
27640- inferredType = aggregateInference;
27631+ const instantiatedConstraint = instantiateType(getConstraintOfTypeParameter(inference.typeParameter), context.nonFixingMapper);
27632+ inferredType = getAggregateInference(inference, instantiatedConstraint, context.compareTypes, context.nonFixingMapper);
2764127633 }
2764227634 else if (context.flags & InferenceFlags.NoDefault) {
2764327635 // We use silentNeverType as the wildcard that signals no inferences.
0 commit comments