Skip to content

Commit f55b3ef

Browse files
committed
Preserve modifiers in isomorphic mapped types
1 parent e313fef commit f55b3ef

File tree

1 file changed

+17
-9
lines changed

1 file changed

+17
-9
lines changed

src/compiler/checker.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4497,12 +4497,14 @@ namespace ts {
44974497
// Resolve upfront such that recursive references see an empty object type.
44984498
setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, undefined, undefined);
44994499
// In { [P in K]: T }, we refer to P as the type parameter type, K as the constraint type,
4500-
// and T as the template type.
4500+
// and T as the template type. If K is of the form 'keyof S', the mapped type and S are
4501+
// isomorphic and we copy property modifiers from corresponding properties in S.
45014502
const typeParameter = getTypeParameterFromMappedType(type);
45024503
const constraintType = getConstraintTypeFromMappedType(type);
4504+
const isomorphicType = getIsomorphicTypeFromMappedType(type);
45034505
const templateType = getTemplateTypeFromMappedType(type);
4504-
const isReadonly = !!type.declaration.readonlyToken;
4505-
const isOptional = !!type.declaration.questionToken;
4506+
const templateReadonly = !!type.declaration.readonlyToken;
4507+
const templateOptional = !!type.declaration.questionToken;
45064508
// First, if the constraint type is a type parameter, obtain the base constraint. Then,
45074509
// if the key type is a 'keyof X', obtain 'keyof C' where C is the base constraint of X.
45084510
// Finally, iterate over the constituents of the resulting iteration type.
@@ -4515,18 +4517,19 @@ namespace ts {
45154517
const iterationMapper = createUnaryTypeMapper(typeParameter, t);
45164518
const templateMapper = type.mapper ? combineTypeMappers(type.mapper, iterationMapper) : iterationMapper;
45174519
const propType = instantiateType(templateType, templateMapper);
4518-
// If the current iteration type constituent is a literal type, create a property.
4519-
// Otherwise, for type string create a string index signature and for type number
4520-
// create a numeric index signature.
4521-
if (t.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral)) {
4520+
// If the current iteration type constituent is a string literal type, create a property.
4521+
// Otherwise, for type string create a string index signature.
4522+
if (t.flags & TypeFlags.StringLiteral) {
45224523
const propName = (<LiteralType>t).text;
4524+
const isomorphicProp = isomorphicType && getPropertyOfType(isomorphicType, propName);
4525+
const isOptional = templateOptional || !!(isomorphicProp && isomorphicProp.flags & SymbolFlags.Optional);
45234526
const prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName);
45244527
prop.type = addOptionality(propType, isOptional);
4525-
prop.isReadonly = isReadonly;
4528+
prop.isReadonly = templateReadonly || isomorphicProp && isReadonlySymbol(isomorphicProp);
45264529
members[propName] = prop;
45274530
}
45284531
else if (t.flags & TypeFlags.String) {
4529-
stringIndexInfo = createIndexInfo(propType, isReadonly);
4532+
stringIndexInfo = createIndexInfo(propType, templateReadonly);
45304533
}
45314534
});
45324535
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined);
@@ -4549,6 +4552,11 @@ namespace ts {
45494552
unknownType);
45504553
}
45514554

4555+
function getIsomorphicTypeFromMappedType(type: MappedType) {
4556+
const constraint = getConstraintDeclaration(getTypeParameterFromMappedType(type));
4557+
return constraint.kind === SyntaxKind.TypeOperator ? instantiateType(getTypeFromTypeNode((<TypeOperatorNode>constraint).type), type.mapper || identityMapper) : undefined;
4558+
}
4559+
45524560
function getErasedTemplateTypeFromMappedType(type: MappedType) {
45534561
return instantiateType(getTemplateTypeFromMappedType(type), createUnaryTypeMapper(getTypeParameterFromMappedType(type), anyType));
45544562
}

0 commit comments

Comments
 (0)