@@ -4512,12 +4512,11 @@ namespace ts {
4512
4512
// Resolve upfront such that recursive references see an empty object type.
4513
4513
setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, undefined, undefined);
4514
4514
// In { [P in K]: T }, we refer to P as the type parameter type, K as the constraint type,
4515
- // and T as the template type. If K is of the form 'keyof S', the mapped type and S are
4516
- // homomorphic and we copy property modifiers from corresponding properties in S.
4515
+ // and T as the template type.
4517
4516
const typeParameter = getTypeParameterFromMappedType(type);
4518
4517
const constraintType = getConstraintTypeFromMappedType(type);
4519
- const homomorphicType = getHomomorphicTypeFromMappedType(type);
4520
4518
const templateType = getTemplateTypeFromMappedType(type);
4519
+ const modifiersType = getModifiersTypeFromMappedType(type);
4521
4520
const templateReadonly = !!type.declaration.readonlyToken;
4522
4521
const templateOptional = !!type.declaration.questionToken;
4523
4522
// First, if the constraint type is a type parameter, obtain the base constraint. Then,
@@ -4536,11 +4535,11 @@ namespace ts {
4536
4535
// Otherwise, for type string create a string index signature.
4537
4536
if (t.flags & TypeFlags.StringLiteral) {
4538
4537
const propName = (<LiteralType>t).text;
4539
- const homomorphicProp = homomorphicType && getPropertyOfType(homomorphicType , propName);
4540
- const isOptional = templateOptional || !!(homomorphicProp && homomorphicProp .flags & SymbolFlags.Optional);
4538
+ const modifiersProp = getPropertyOfType(modifiersType , propName);
4539
+ const isOptional = templateOptional || !!(modifiersProp && modifiersProp .flags & SymbolFlags.Optional);
4541
4540
const prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName);
4542
4541
prop.type = propType;
4543
- prop.isReadonly = templateReadonly || homomorphicProp && isReadonlySymbol(homomorphicProp );
4542
+ prop.isReadonly = templateReadonly || modifiersProp && isReadonlySymbol(modifiersProp );
4544
4543
members[propName] = prop;
4545
4544
}
4546
4545
else if (t.flags & TypeFlags.String) {
@@ -4567,9 +4566,16 @@ namespace ts {
4567
4566
unknownType);
4568
4567
}
4569
4568
4570
- function getHomomorphicTypeFromMappedType(type: MappedType) {
4571
- const constraint = getConstraintDeclaration(getTypeParameterFromMappedType(type));
4572
- return constraint.kind === SyntaxKind.TypeOperator ? instantiateType(getTypeFromTypeNode((<TypeOperatorNode>constraint).type), type.mapper || identityMapper) : undefined;
4569
+ function getModifiersTypeFromMappedType(type: MappedType) {
4570
+ if (!type.modifiersType) {
4571
+ // If the mapped type was declared as { [P in keyof T]: X } or as { [P in K]: X }, where
4572
+ // K is constrained to 'K extends keyof T', then we will copy property modifiers from T.
4573
+ const declaredType = <MappedType>getTypeFromMappedTypeNode(type.declaration);
4574
+ const constraint = getConstraintTypeFromMappedType(declaredType);
4575
+ const extendedConstraint = constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(<TypeParameter>constraint) : constraint;
4576
+ type.modifiersType = extendedConstraint.flags & TypeFlags.Index ? instantiateType((<IndexType>extendedConstraint).type, type.mapper || identityMapper) : emptyObjectType;
4577
+ }
4578
+ return type.modifiersType;
4573
4579
}
4574
4580
4575
4581
function getErasedTemplateTypeFromMappedType(type: MappedType) {
0 commit comments