From f58e1a2b17ad5299e8ac9624e8a6d1619dc21ee4 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 14 Dec 2016 14:59:00 -0800 Subject: [PATCH] Map both declared properties and string index signatures --- src/compiler/checker.ts | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 26164a528f3..5246bbfc700 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4536,15 +4536,27 @@ namespace ts { const typeParameter = getTypeParameterFromMappedType(type); const constraintType = getConstraintTypeFromMappedType(type); const templateType = getTemplateTypeFromMappedType(type); - const modifiersType = getModifiersTypeFromMappedType(type); + const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); const templateReadonly = !!type.declaration.readonlyToken; const templateOptional = !!type.declaration.questionToken; - // First, if the constraint type is a type parameter, obtain the base constraint. Then, - // if the key type is a 'keyof X', obtain 'keyof C' where C is the base constraint of X. - // Finally, iterate over the constituents of the resulting iteration type. - const keyType = constraintType.flags & TypeFlags.TypeVariable ? getApparentType(constraintType) : constraintType; - const iterationType = keyType.flags & TypeFlags.Index ? getIndexType(getApparentType((keyType).type)) : keyType; - forEachType(iterationType, t => { + if (type.declaration.typeParameter.constraint.kind === SyntaxKind.TypeOperator) { + // We have a { [P in keyof T]: X } + forEachType(getLiteralTypeFromPropertyNames(modifiersType), addMemberForKeyType); + if (getIndexInfoOfType(modifiersType, IndexKind.String)) { + addMemberForKeyType(stringType); + } + } + else { + // First, if the constraint type is a type parameter, obtain the base constraint. Then, + // if the key type is a 'keyof X', obtain 'keyof C' where C is the base constraint of X. + // Finally, iterate over the constituents of the resulting iteration type. + const keyType = constraintType.flags & TypeFlags.TypeVariable ? getApparentType(constraintType) : constraintType; + const iterationType = keyType.flags & TypeFlags.Index ? getIndexType(getApparentType((keyType).type)) : keyType; + forEachType(iterationType, addMemberForKeyType); + } + setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined); + + function addMemberForKeyType(t: Type) { // Create a mapper from T to the current iteration type constituent. Then, if the // mapped type is itself an instantiated type, combine the iteration mapper with the // instantiation mapper. @@ -4565,8 +4577,7 @@ namespace ts { else if (t.flags & TypeFlags.String) { stringIndexInfo = createIndexInfo(propType, templateReadonly); } - }); - setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined); + } } function getTypeParameterFromMappedType(type: MappedType) {