@@ -13689,7 +13689,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
13689
13689
const modifiers = getMappedTypeModifiers(type.mappedType);
13690
13690
const readonlyMask = modifiers & MappedTypeModifiers.IncludeReadonly ? false : true;
13691
13691
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;
13693
13693
const members = createSymbolTable();
13694
13694
const limitedConstraint = getLimitedConstraint(type);
13695
13695
for (const prop of getPropertiesOfType(type.source)) {
@@ -13724,6 +13724,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
13724
13724
inferredProp.links.mappedType = type.mappedType;
13725
13725
inferredProp.links.constraintType = type.constraintType;
13726
13726
}
13727
+ if (type.inferenceMapper) {
13728
+ inferredProp.links.inferenceMapper = type.inferenceMapper;
13729
+ }
13727
13730
members.set(prop.escapedName, inferredProp);
13728
13731
}
13729
13732
setStructuredTypeMembers(type, members, emptyArray, emptyArray, indexInfos);
@@ -13993,13 +13996,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
13993
13996
else if ((type as ObjectType).objectFlags & ObjectFlags.ClassOrInterface) {
13994
13997
resolveClassOrInterfaceMembers(type as InterfaceType);
13995
13998
}
13996
- else if ((type as ReverseMappedType ).objectFlags & ObjectFlags.ReverseMapped) {
13999
+ else if ((type as ObjectType ).objectFlags & ObjectFlags.ReverseMapped) {
13997
14000
resolveReverseMappedTypeMembers(type as ReverseMappedType);
13998
14001
}
13999
14002
else if ((type as ObjectType).objectFlags & ObjectFlags.Anonymous) {
14000
14003
resolveAnonymousTypeMembers(type as AnonymousType);
14001
14004
}
14002
- else if ((type as MappedType ).objectFlags & ObjectFlags.Mapped) {
14005
+ else if ((type as ObjectType ).objectFlags & ObjectFlags.Mapped) {
14003
14006
resolveMappedTypeMembers(type as MappedType);
14004
14007
}
14005
14008
else {
@@ -25065,10 +25068,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
25065
25068
// For arrays and tuples we infer new arrays and tuples where the reverse mapping has been
25066
25069
// applied to the element type(s).
25067
25070
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));
25069
25072
}
25070
25073
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));
25072
25075
const elementFlags = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ?
25073
25076
sameMap(source.target.elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) :
25074
25077
source.target.elementFlags;
@@ -25086,17 +25089,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
25086
25089
function getTypeOfReverseMappedSymbol(symbol: ReverseMappedSymbol) {
25087
25090
const links = getSymbolLinks(symbol);
25088
25091
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);
25090
25094
}
25091
25095
return links.type;
25092
25096
}
25093
25097
25094
- function inferReverseMappedType(sourceType: Type, target: MappedType, constraint: IndexType): Type {
25098
+ function inferReverseMappedType(propertyNameType: Type, sourceType: Type, target: MappedType, constraint: IndexType, inferenceMapper?: TypeMapper ): Type {
25095
25099
const typeParameter = getIndexedAccessType(constraint.type, getTypeParameterFromMappedType(target)) as TypeParameter;
25096
25100
const templateType = getTemplateTypeFromMappedType(target);
25097
25101
const inference = createInferenceInfo(typeParameter);
25098
25102
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;
25100
25112
}
25101
25113
25102
25114
function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): IterableIterator<Symbol> {
@@ -26185,10 +26197,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
26185
26197
const constraint = getConstraintOfTypeParameter(inference.typeParameter);
26186
26198
if (constraint) {
26187
26199
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
+ }
26188
26204
if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) {
26189
26205
// If the fallback type satisfies the constraint, we pick it. Otherwise, we pick the constraint.
26190
26206
inference.inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint;
26191
26207
}
26208
+ if (inferredType && inferredType.flags & TypeFlags.Object && (inferredType as ObjectType).objectFlags & ObjectFlags.ReverseMapped) {
26209
+ (inferredType as ReverseMappedType).inferenceMapper = undefined;
26210
+ }
26192
26211
}
26193
26212
}
26194
26213
0 commit comments