@@ -2108,7 +2108,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21082108 var unreachableNeverType = createIntrinsicType(TypeFlags.Never, "never", /*objectFlags*/ undefined, "unreachable");
21092109 var nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object");
21102110 var stringOrNumberType = getUnionType([stringType, numberType]);
2111- var stringNumberSymbolType = getUnionType([stringType, numberType, esSymbolType]) as UnionType ;
2111+ var stringNumberSymbolType = getUnionType([stringType, numberType, esSymbolType]);
21122112 var numberOrBigIntType = getUnionType([numberType, bigintType]);
21132113 var templateConstraintType = getUnionType([stringType, numberType, booleanType, bigintType, nullType, undefinedType]) as UnionType;
21142114 var numericStringType = getTemplateLiteralType(["", ""], [numberType]); // The `${number}` type
@@ -2144,9 +2144,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21442144 var unknownEmptyObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
21452145 var unknownUnionType = strictNullChecks ? getUnionType([undefinedType, nullType, unknownEmptyObjectType]) : unknownType;
21462146
2147- var allKeysUnknownType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, map(stringNumberSymbolType.types, t => createIndexInfo(t, unknownType, /*isReadonly*/ false))); // { [k: PropertyKey]: unknown }
2148- var allKeysAllKeysUnknownType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, map(stringNumberSymbolType.types, t => createIndexInfo(t, allKeysUnknownType, /*isReadonly*/ false))); // { [k: PropertyKey]: { [k: PropertyKey]: unknown } }
2149-
21502147 var emptyGenericType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray) as ObjectType as GenericType;
21512148 emptyGenericType.instantiations = new Map<string, TypeReference>();
21522149
@@ -26441,18 +26438,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2644126438 const templateType = getTemplateTypeFromMappedType(target);
2644226439 const inference = createInferenceInfo(inferenceTarget);
2644326440 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;
26441+ return getTypeFromInference(inference) || unknownType;
2645626442 }
2645726443
2645826444 function inferReverseMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {
@@ -26521,7 +26507,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2652126507 function getTypeFromInference(inference: InferenceInfo) {
2652226508 return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) :
2652326509 inference.contraCandidates ? getIntersectionType(inference.contraCandidates) :
26524- undefined ;
26510+ getAggregateInference(inference) ;
2652526511 }
2652626512
2652726513 function hasSkipDirectInferenceFlag(node: Node) {
@@ -27568,6 +27554,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2756827554 return getWidenedType(unwidenedType);
2756927555 }
2757027556
27557+ function getAggregateInference(inference: InferenceInfo, constraintType?: Type, compareTypes?: TypeComparer, mapper?: TypeMapper | undefined): Type | undefined {
27558+ if (!inference.indexes) {
27559+ return undefined;
27560+ }
27561+ const typeEraser = createTypeEraser([inference.typeParameter.flags & TypeFlags.IndexedAccess ? (inference.typeParameter as IndexedAccessType).objectType : inference.typeParameter]);
27562+ const aggregateInference = instantiateType(getIntersectionType(inference.indexes), mapper ? mergeTypeMappers(typeEraser, mapper) : typeEraser);
27563+ if (getReducedType(aggregateInference).flags & TypeFlags.Never) {
27564+ // `never` inference isn't that useful of an inference given its assignable to every other type
27565+ return undefined;
27566+ }
27567+ if (!constraintType || (compareTypes ??= compareTypesAssignable)(aggregateInference, getTypeWithThisArgument(constraintType, aggregateInference))) {
27568+ return aggregateInference;
27569+ }
27570+ if (constraintType.flags & TypeFlags.Union) {
27571+ const discriminantProps = findDiscriminantProperties(getPropertiesOfType(aggregateInference), constraintType);
27572+ if (discriminantProps) {
27573+ let match: Type | undefined;
27574+ findDiscriminant:
27575+ for (const p of discriminantProps) {
27576+ const candidatePropType = getTypeOfPropertyOfType(aggregateInference, p.escapedName);
27577+ for (const type of (constraintType as UnionType).types) {
27578+ const propType = getTypeOfPropertyOfType(type, p.escapedName);
27579+ if (propType && candidatePropType && isTypeAssignableTo(candidatePropType, propType)) {
27580+ if (match && match !== type) {
27581+ match = undefined;
27582+ break findDiscriminant;
27583+ }
27584+ else {
27585+ match = type;
27586+ }
27587+ }
27588+ }
27589+ }
27590+ if (match) {
27591+ const combinedType = getSpreadType(match, aggregateInference, /*symbol*/ undefined, /*propegatedFlags*/ 0, /*readonly*/ false);
27592+ if (compareTypes(combinedType, getTypeWithThisArgument(constraintType, combinedType))) {
27593+ return combinedType;
27594+ }
27595+ }
27596+ }
27597+ }
27598+ // if the aggregate inference isn't assignable to the constraint return undefined
27599+ // this way the compiler keeps preferring the default type
27600+ return undefined;
27601+ }
27602+
2757127603 function getInferredType(context: InferenceContext, index: number): Type {
2757227604 const inference = context.inferences[index];
2757327605 if (!inference.inferredType) {
@@ -27593,51 +27625,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2759327625 fallbackType = preferCovariantType ? inferredContravariantType : inferredCovariantType;
2759427626 }
2759527627 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;
27628+ const instantiatedConstraint = instantiateType(getConstraintOfTypeParameter(inference.typeParameter), context.nonFixingMapper);
27629+ inferredType = getAggregateInference(inference, instantiatedConstraint, context.compareTypes, context.nonFixingMapper);
2764127630 }
2764227631 else if (context.flags & InferenceFlags.NoDefault) {
2764327632 // We use silentNeverType as the wildcard that signals no inferences.
0 commit comments