@@ -6786,7 +6786,7 @@ namespace ts {
6786
6786
const modifiers = getMappedTypeModifiers(type.mappedType);
6787
6787
const readonlyMask = modifiers & MappedTypeModifiers.IncludeReadonly ? false : true;
6788
6788
const optionalMask = modifiers & MappedTypeModifiers.IncludeOptional ? 0 : SymbolFlags.Optional;
6789
- const stringIndexInfo = indexInfo && createIndexInfo(inferReverseMappedType(indexInfo.type, type.mappedType), readonlyMask && indexInfo.isReadonly);
6789
+ const stringIndexInfo = indexInfo && createIndexInfo(inferReverseMappedType(indexInfo.type, type.mappedType, type.constraintType ), readonlyMask && indexInfo.isReadonly);
6790
6790
const members = createSymbolTable();
6791
6791
for (const prop of getPropertiesOfType(type.source)) {
6792
6792
const checkFlags = CheckFlags.ReverseMapped | (readonlyMask && isReadonlySymbol(prop) ? CheckFlags.Readonly : 0);
@@ -6795,6 +6795,7 @@ namespace ts {
6795
6795
inferredProp.nameType = prop.nameType;
6796
6796
inferredProp.propertyType = getTypeOfSymbol(prop);
6797
6797
inferredProp.mappedType = type.mappedType;
6798
+ inferredProp.constraintType = type.constraintType;
6798
6799
members.set(prop.escapedName, inferredProp);
6799
6800
}
6800
6801
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined);
@@ -13493,18 +13494,18 @@ namespace ts {
13493
13494
* property is computed by inferring from the source property type to X for the type
13494
13495
* variable T[P] (i.e. we treat the type T[P] as the type variable we're inferring for).
13495
13496
*/
13496
- function inferTypeForHomomorphicMappedType(source: Type, target: MappedType): Type | undefined {
13497
- const key = source.id + "," + target.id;
13497
+ function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, constraint: IndexType ): Type | undefined {
13498
+ const key = source.id + "," + target.id + "," + constraint.id ;
13498
13499
if (reverseMappedCache.has(key)) {
13499
13500
return reverseMappedCache.get(key);
13500
13501
}
13501
13502
reverseMappedCache.set(key, undefined);
13502
- const type = createReverseMappedType(source, target);
13503
+ const type = createReverseMappedType(source, target, constraint );
13503
13504
reverseMappedCache.set(key, type);
13504
13505
return type;
13505
13506
}
13506
13507
13507
- function createReverseMappedType(source: Type, target: MappedType) {
13508
+ function createReverseMappedType(source: Type, target: MappedType, constraint: IndexType ) {
13508
13509
const properties = getPropertiesOfType(source);
13509
13510
if (properties.length === 0 && !getIndexInfoOfType(source, IndexKind.String)) {
13510
13511
return undefined;
@@ -13519,13 +13520,13 @@ namespace ts {
13519
13520
// For arrays and tuples we infer new arrays and tuples where the reverse mapping has been
13520
13521
// applied to the element type(s).
13521
13522
if (isArrayType(source)) {
13522
- return createArrayType(inferReverseMappedType((<TypeReference>source).typeArguments![0], target));
13523
+ return createArrayType(inferReverseMappedType((<TypeReference>source).typeArguments![0], target, constraint ));
13523
13524
}
13524
13525
if (isReadonlyArrayType(source)) {
13525
- return createReadonlyArrayType(inferReverseMappedType((<TypeReference>source).typeArguments![0], target));
13526
+ return createReadonlyArrayType(inferReverseMappedType((<TypeReference>source).typeArguments![0], target, constraint ));
13526
13527
}
13527
13528
if (isTupleType(source)) {
13528
- const elementTypes = map(source.typeArguments || emptyArray, t => inferReverseMappedType(t, target));
13529
+ const elementTypes = map(source.typeArguments || emptyArray, t => inferReverseMappedType(t, target, constraint ));
13529
13530
const minLength = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ?
13530
13531
getTypeReferenceArity(source) - (source.target.hasRestElement ? 1 : 0) : source.target.minLength;
13531
13532
return createTupleType(elementTypes, minLength, source.target.hasRestElement, source.target.associatedNames);
@@ -13535,15 +13536,16 @@ namespace ts {
13535
13536
const reversed = createObjectType(ObjectFlags.ReverseMapped | ObjectFlags.Anonymous, /*symbol*/ undefined) as ReverseMappedType;
13536
13537
reversed.source = source;
13537
13538
reversed.mappedType = target;
13539
+ reversed.constraintType = constraint;
13538
13540
return reversed;
13539
13541
}
13540
13542
13541
13543
function getTypeOfReverseMappedSymbol(symbol: ReverseMappedSymbol) {
13542
- return inferReverseMappedType(symbol.propertyType, symbol.mappedType);
13544
+ return inferReverseMappedType(symbol.propertyType, symbol.mappedType, symbol.constraintType );
13543
13545
}
13544
13546
13545
- function inferReverseMappedType(sourceType: Type, target: MappedType): Type {
13546
- const typeParameter = <TypeParameter>getIndexedAccessType((<IndexType>getConstraintTypeFromMappedType(target)) .type, getTypeParameterFromMappedType(target));
13547
+ function inferReverseMappedType(sourceType: Type, target: MappedType, constraint: IndexType ): Type {
13548
+ const typeParameter = <TypeParameter>getIndexedAccessType(constraint .type, getTypeParameterFromMappedType(target));
13547
13549
const templateType = getTemplateTypeFromMappedType(target);
13548
13550
const inference = createInferenceInfo(typeParameter);
13549
13551
inferTypes([inference], sourceType, templateType);
@@ -13841,6 +13843,44 @@ namespace ts {
13841
13843
return undefined;
13842
13844
}
13843
13845
13846
+ function inferFromMappedTypeConstraint(source: Type, target: Type, constraintType: Type): boolean {
13847
+ if (constraintType.flags & TypeFlags.Union) {
13848
+ let result = false;
13849
+ for (const type of (constraintType as UnionType).types) {
13850
+ result = inferFromMappedTypeConstraint(source, target, type) || result;
13851
+ }
13852
+ return result;
13853
+ }
13854
+ if (constraintType.flags & TypeFlags.Index) {
13855
+ // We're inferring from some source type S to a homomorphic mapped type { [P in keyof T]: X },
13856
+ // where T is a type variable. Use inferTypeForHomomorphicMappedType to infer a suitable source
13857
+ // type and then make a secondary inference from that type to T. We make a secondary inference
13858
+ // such that direct inferences to T get priority over inferences to Partial<T>, for example.
13859
+ const inference = getInferenceInfoForType((<IndexType>constraintType).type);
13860
+ if (inference && !inference.isFixed) {
13861
+ const inferredType = inferTypeForHomomorphicMappedType(source, <MappedType>target, constraintType as IndexType);
13862
+ if (inferredType) {
13863
+ const savePriority = priority;
13864
+ priority |= InferencePriority.HomomorphicMappedType;
13865
+ inferFromTypes(inferredType, inference.typeParameter);
13866
+ priority = savePriority;
13867
+ }
13868
+ }
13869
+ return true;
13870
+ }
13871
+ if (constraintType.flags & TypeFlags.TypeParameter) {
13872
+ // We're inferring from some source type S to a mapped type { [P in T]: X }, where T is a type
13873
+ // parameter. Infer from 'keyof S' to T and infer from a union of each property type in S to X.
13874
+ const savePriority = priority;
13875
+ priority |= InferencePriority.MappedTypeConstraint;
13876
+ inferFromTypes(getIndexType(source), constraintType);
13877
+ priority = savePriority;
13878
+ inferFromTypes(getUnionType(map(getPropertiesOfType(source), getTypeOfSymbol)), getTemplateTypeFromMappedType(<MappedType>target));
13879
+ return true;
13880
+ }
13881
+ return false;
13882
+ }
13883
+
13844
13884
function inferFromObjectTypes(source: Type, target: Type) {
13845
13885
if (isGenericMappedType(source) && isGenericMappedType(target)) {
13846
13886
// The source and target types are generic types { [P in S]: X } and { [P in T]: Y }, so we infer
@@ -13850,31 +13890,7 @@ namespace ts {
13850
13890
}
13851
13891
if (getObjectFlags(target) & ObjectFlags.Mapped) {
13852
13892
const constraintType = getConstraintTypeFromMappedType(<MappedType>target);
13853
- if (constraintType.flags & TypeFlags.Index) {
13854
- // We're inferring from some source type S to a homomorphic mapped type { [P in keyof T]: X },
13855
- // where T is a type variable. Use inferTypeForHomomorphicMappedType to infer a suitable source
13856
- // type and then make a secondary inference from that type to T. We make a secondary inference
13857
- // such that direct inferences to T get priority over inferences to Partial<T>, for example.
13858
- const inference = getInferenceInfoForType((<IndexType>constraintType).type);
13859
- if (inference && !inference.isFixed) {
13860
- const inferredType = inferTypeForHomomorphicMappedType(source, <MappedType>target);
13861
- if (inferredType) {
13862
- const savePriority = priority;
13863
- priority |= InferencePriority.HomomorphicMappedType;
13864
- inferFromTypes(inferredType, inference.typeParameter);
13865
- priority = savePriority;
13866
- }
13867
- }
13868
- return;
13869
- }
13870
- if (constraintType.flags & TypeFlags.TypeParameter) {
13871
- // We're inferring from some source type S to a mapped type { [P in T]: X }, where T is a type
13872
- // parameter. Infer from 'keyof S' to T and infer from a union of each property type in S to X.
13873
- const savePriority = priority;
13874
- priority |= InferencePriority.MappedTypeConstraint;
13875
- inferFromTypes(getIndexType(source), constraintType);
13876
- priority = savePriority;
13877
- inferFromTypes(getUnionType(map(getPropertiesOfType(source), getTypeOfSymbol)), getTemplateTypeFromMappedType(<MappedType>target));
13893
+ if (inferFromMappedTypeConstraint(source, target, constraintType)) {
13878
13894
return;
13879
13895
}
13880
13896
}
0 commit comments