Skip to content

Commit 33b5125

Browse files
committed
Pick<T, K> and similar mapped types propagate modifiers from T
1 parent 798d080 commit 33b5125

File tree

2 files changed

+16
-9
lines changed

2 files changed

+16
-9
lines changed

src/compiler/checker.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4512,12 +4512,11 @@ namespace ts {
45124512
// Resolve upfront such that recursive references see an empty object type.
45134513
setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, undefined, undefined);
45144514
// 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.
45174516
const typeParameter = getTypeParameterFromMappedType(type);
45184517
const constraintType = getConstraintTypeFromMappedType(type);
4519-
const homomorphicType = getHomomorphicTypeFromMappedType(type);
45204518
const templateType = getTemplateTypeFromMappedType(type);
4519+
const modifiersType = getModifiersTypeFromMappedType(type);
45214520
const templateReadonly = !!type.declaration.readonlyToken;
45224521
const templateOptional = !!type.declaration.questionToken;
45234522
// First, if the constraint type is a type parameter, obtain the base constraint. Then,
@@ -4536,11 +4535,11 @@ namespace ts {
45364535
// Otherwise, for type string create a string index signature.
45374536
if (t.flags & TypeFlags.StringLiteral) {
45384537
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);
45414540
const prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName);
45424541
prop.type = propType;
4543-
prop.isReadonly = templateReadonly || homomorphicProp && isReadonlySymbol(homomorphicProp);
4542+
prop.isReadonly = templateReadonly || modifiersProp && isReadonlySymbol(modifiersProp);
45444543
members[propName] = prop;
45454544
}
45464545
else if (t.flags & TypeFlags.String) {
@@ -4567,9 +4566,16 @@ namespace ts {
45674566
unknownType);
45684567
}
45694568

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;
45734579
}
45744580

45754581
function getErasedTemplateTypeFromMappedType(type: MappedType) {

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2933,6 +2933,7 @@ namespace ts {
29332933
typeParameter?: TypeParameter;
29342934
constraintType?: Type;
29352935
templateType?: Type;
2936+
modifiersType?: Type;
29362937
mapper?: TypeMapper; // Instantiation mapper
29372938
}
29382939

0 commit comments

Comments
 (0)