From 8aef1e6bb14a05401468f9107245615cc8c2dd2b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 8 Nov 2016 06:55:35 -0800 Subject: [PATCH] Type inference for mapped types --- src/compiler/checker.ts | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c0228a97eaf..8349f985f58 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5941,7 +5941,7 @@ namespace ts { if (!links.resolvedType) { const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node.typeParameter)); const constraintType = getConstraintOfTypeParameter(typeParameter); - const keyType = constraintType && constraintType.flags & TypeFlags.TypeParameter ? getApparentType(constraintType) : constraintType; + const keyType = constraintType && constraintType.flags & TypeFlags.TypeParameter ? getApparentTypeOfTypeParameter(constraintType) : constraintType; if (keyType && (keyType.flags & TypeFlags.Index || checkTypeAssignableTo(keyType, stringOrNumberType, node.typeParameter.constraint))) { const type = createObjectType(ObjectFlags.Mapped, node.symbol); type.typeParameter = typeParameter; @@ -8117,9 +8117,11 @@ namespace ts { // we perform type inference (i.e. a type parameter of a generic function). We cache // results for union and intersection types for performance reasons. function couldContainTypeParameters(type: Type): boolean { + const objectFlags = getObjectFlags(type); return !!(type.flags & TypeFlags.TypeParameter || - getObjectFlags(type) & ObjectFlags.Reference && forEach((type).typeArguments, couldContainTypeParameters) || - getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) || + objectFlags & ObjectFlags.Reference && forEach((type).typeArguments, couldContainTypeParameters) || + objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) || + objectFlags & ObjectFlags.Mapped || type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(type)); } @@ -8267,6 +8269,19 @@ namespace ts { } } else { + if (getObjectFlags(target) & ObjectFlags.Mapped) { + const constraintType = getConstraintTypeFromMappedType(target); + if (getObjectFlags(source) & ObjectFlags.Mapped) { + inferFromTypes(getConstraintTypeFromMappedType(source), constraintType); + inferFromTypes(getTemplateTypeFromMappedType(source), getTemplateTypeFromMappedType(target)); + return; + } + if (constraintType.flags & TypeFlags.TypeParameter) { + inferFromTypes(getIndexType(source), constraintType); + inferFromTypes(getUnionType(map(getPropertiesOfType(source), getTypeOfSymbol)), getTemplateTypeFromMappedType(target)); + return; + } + } source = getApparentType(source); if (source.flags & TypeFlags.Object) { if (isInProcess(source, target)) {