Properly compute lower bound of key type in a mapped type

This commit is contained in:
Anders Hejlsberg
2018-12-21 12:50:53 -08:00
parent 08022d57c8
commit 565ab7a971

View File

@@ -7084,6 +7084,39 @@ namespace ts {
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined);
}
// Return the lower bound of the key type in a mapped type. Intuitively, the lower
// bound includes those keys that are known to always be present, for example because
// because of constraints on type parameters (e.g. 'keyof T' for a constrained T).
function getLowerBoundOfKeyType(type: Type): Type {
if (type.flags & (TypeFlags.Any | TypeFlags.Primitive)) {
return type;
}
if (type.flags & TypeFlags.Index) {
return getIndexType(getApparentType((<IndexType>type).type));
}
if (type.flags & TypeFlags.Conditional) {
return getLowerBoundOfConditionalType(<ConditionalType>type);
}
if (type.flags & TypeFlags.Union) {
return getUnionType(sameMap((<UnionType>type).types, getLowerBoundOfKeyType));
}
if (type.flags & TypeFlags.Intersection) {
return getIntersectionType(sameMap((<UnionType>type).types, getLowerBoundOfKeyType));
}
return neverType;
}
function getLowerBoundOfConditionalType(type: ConditionalType) {
if (type.root.isDistributive) {
const constraint = getLowerBoundOfKeyType(type.checkType);
if (constraint !== type.checkType) {
const mapper = makeUnaryTypeMapper(type.root.checkType, constraint);
return getConditionalTypeInstantiation(type, combineTypeMappers(mapper, type.mapper));
}
}
return type;
}
/** Resolve the members of a mapped type { [P in K]: T } */
function resolveMappedTypeMembers(type: MappedType) {
const members: SymbolTable = createSymbolTable();
@@ -7112,10 +7145,7 @@ namespace ts {
}
}
else {
// If the key type is a 'keyof X', obtain 'keyof C' where C is the base constraint of X.
// Then iterate over the constituents of the key type.
const iterationType = constraintType.flags & TypeFlags.Index ? getIndexType(getApparentType((<IndexType>constraintType).type)) : constraintType;
forEachType(iterationType, addMemberForKeyType);
forEachType(getLowerBoundOfKeyType(constraintType), addMemberForKeyType);
}
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);