@@ -13689,7 +13689,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1368913689 const modifiers = getMappedTypeModifiers(type.mappedType);
1369013690 const readonlyMask = modifiers & MappedTypeModifiers.IncludeReadonly ? false : true;
1369113691 const optionalMask = modifiers & MappedTypeModifiers.IncludeOptional ? 0 : SymbolFlags.Optional;
13692- const indexInfos = indexInfo ? [createIndexInfo(stringType, inferReverseMappedType(indexInfo.type, type.mappedType, type.constraintType), readonlyMask && indexInfo.isReadonly)] : emptyArray;
13692+ const indexInfos = indexInfo ? [createIndexInfo(stringType, inferReverseMappedType(indexInfo.keyType, indexInfo. type, type.mappedType, type.constraintType, type.inferenceMapper ), readonlyMask && indexInfo.isReadonly)] : emptyArray;
1369313693 const members = createSymbolTable();
1369413694 const limitedConstraint = getLimitedConstraint(type);
1369513695 for (const prop of getPropertiesOfType(type.source)) {
@@ -13724,6 +13724,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1372413724 inferredProp.links.mappedType = type.mappedType;
1372513725 inferredProp.links.constraintType = type.constraintType;
1372613726 }
13727+ if (type.inferenceMapper) {
13728+ inferredProp.links.inferenceMapper = type.inferenceMapper;
13729+ }
1372713730 members.set(prop.escapedName, inferredProp);
1372813731 }
1372913732 setStructuredTypeMembers(type, members, emptyArray, emptyArray, indexInfos);
@@ -13993,13 +13996,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1399313996 else if ((type as ObjectType).objectFlags & ObjectFlags.ClassOrInterface) {
1399413997 resolveClassOrInterfaceMembers(type as InterfaceType);
1399513998 }
13996- else if ((type as ReverseMappedType ).objectFlags & ObjectFlags.ReverseMapped) {
13999+ else if ((type as ObjectType ).objectFlags & ObjectFlags.ReverseMapped) {
1399714000 resolveReverseMappedTypeMembers(type as ReverseMappedType);
1399814001 }
1399914002 else if ((type as ObjectType).objectFlags & ObjectFlags.Anonymous) {
1400014003 resolveAnonymousTypeMembers(type as AnonymousType);
1400114004 }
14002- else if ((type as MappedType ).objectFlags & ObjectFlags.Mapped) {
14005+ else if ((type as ObjectType ).objectFlags & ObjectFlags.Mapped) {
1400314006 resolveMappedTypeMembers(type as MappedType);
1400414007 }
1400514008 else {
@@ -25065,10 +25068,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2506525068 // For arrays and tuples we infer new arrays and tuples where the reverse mapping has been
2506625069 // applied to the element type(s).
2506725070 if (isArrayType(source)) {
25068- return createArrayType(inferReverseMappedType(getTypeArguments(source)[0], target, constraint), isReadonlyArrayType(source));
25071+ return createArrayType(inferReverseMappedType(numberType, getTypeArguments(source)[0], target, constraint), isReadonlyArrayType(source));
2506925072 }
2507025073 if (isTupleType(source)) {
25071- const elementTypes = map(getElementTypes(source), t => inferReverseMappedType(t, target, constraint));
25074+ const elementTypes = map(getElementTypes(source), (t, i) => inferReverseMappedType(getStringLiteralType("" + i), t, target, constraint));
2507225075 const elementFlags = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ?
2507325076 sameMap(source.target.elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) :
2507425077 source.target.elementFlags;
@@ -25086,17 +25089,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2508625089 function getTypeOfReverseMappedSymbol(symbol: ReverseMappedSymbol) {
2508725090 const links = getSymbolLinks(symbol);
2508825091 if (!links.type) {
25089- links.type = inferReverseMappedType(symbol.links.propertyType, symbol.links.mappedType, symbol.links.constraintType);
25092+ const propertyNameType = getStringLiteralType(unescapeLeadingUnderscores(symbol.escapedName));
25093+ links.type = inferReverseMappedType(propertyNameType, symbol.links.propertyType, symbol.links.mappedType, symbol.links.constraintType, symbol.links.inferenceMapper);
2509025094 }
2509125095 return links.type;
2509225096 }
2509325097
25094- function inferReverseMappedType(sourceType: Type, target: MappedType, constraint: IndexType): Type {
25098+ function inferReverseMappedType(propertyNameType: Type, sourceType: Type, target: MappedType, constraint: IndexType, inferenceMapper?: TypeMapper ): Type {
2509525099 const typeParameter = getIndexedAccessType(constraint.type, getTypeParameterFromMappedType(target)) as TypeParameter;
2509625100 const templateType = getTemplateTypeFromMappedType(target);
2509725101 const inference = createInferenceInfo(typeParameter);
2509825102 inferTypes([inference], sourceType, templateType);
25099- return getTypeFromInference(inference) || getBaseConstraintOfType(typeParameter) || unknownType;
25103+ const inferredType = getTypeFromInference(inference);
25104+ if (inferredType) {
25105+ return inferredType;
25106+ }
25107+ if (!inferenceMapper) {
25108+ return getBaseConstraintOfType(typeParameter) || unknownType;
25109+ }
25110+
25111+ return instantiateType(getConstraintOfType(getIndexedAccessType(constraint.type, propertyNameType)), inferenceMapper) || unknownType;
2510025112 }
2510125113
2510225114 function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): IterableIterator<Symbol> {
@@ -26185,10 +26197,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2618526197 const constraint = getConstraintOfTypeParameter(inference.typeParameter);
2618626198 if (constraint) {
2618726199 const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper);
26200+ // TODO: decide what to do about fallback type
26201+ if (inferredType && inferredType.flags & TypeFlags.Object && (inferredType as ObjectType).objectFlags & ObjectFlags.ReverseMapped) {
26202+ (inferredType as ReverseMappedType).inferenceMapper = context.nonFixingMapper;
26203+ }
2618826204 if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) {
2618926205 // If the fallback type satisfies the constraint, we pick it. Otherwise, we pick the constraint.
2619026206 inference.inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint;
2619126207 }
26208+ if (inferredType && inferredType.flags & TypeFlags.Object && (inferredType as ObjectType).objectFlags & ObjectFlags.ReverseMapped) {
26209+ (inferredType as ReverseMappedType).inferenceMapper = undefined;
26210+ }
2619226211 }
2619326212 }
2619426213
0 commit comments