Don't reduce 'keyof M' for mapped types with non-distributive 'as' clauses (#41186)

* Don't reduce 'keyof M' for mapped types with non-distributive as clauses

* Add regression test

* Accept new baselines
This commit is contained in:
Anders Hejlsberg
2020-10-21 12:16:46 -07:00
committed by GitHub
parent 672861abc6
commit 5d021b401a
5 changed files with 223 additions and 1 deletions

View File

@@ -13475,6 +13475,19 @@ namespace ts {
constraint;
}
// Ordinarily we reduce a keyof M where M is a mapped type { [P in K as N<P>]: X } to simply N<K>. This however presumes
// that N distributes over union types, i.e. that N<A | B | C> is equivalent to N<A> | N<B> | N<C>. That presumption is
// generally true, except when N is a non-distributive conditional type or an instantiable type with non-distributive
// conditional type as a constituent. In those cases, we cannot reduce keyof M and need to preserve it as is.
function isNonDistributiveNameType(type: Type | undefined): boolean {
return !!(type && (
type.flags & TypeFlags.Conditional && !(<ConditionalType>type).root.isDistributive ||
type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) && some((<UnionOrIntersectionType | TemplateLiteralType>type).types, isNonDistributiveNameType) ||
type.flags & (TypeFlags.Index | TypeFlags.StringMapping) && isNonDistributiveNameType((<IndexType | StringMappingType>type).type) ||
type.flags & TypeFlags.IndexedAccess && isNonDistributiveNameType((<IndexedAccessType>type).indexType) ||
type.flags & TypeFlags.Substitution && isNonDistributiveNameType((<SubstitutionType>type).substitute)));
}
function getLiteralTypeFromPropertyName(name: PropertyName) {
if (isPrivateIdentifier(name)) {
return neverType;
@@ -13522,7 +13535,7 @@ namespace ts {
type = getReducedType(type);
return type.flags & TypeFlags.Union ? getIntersectionType(map((<IntersectionType>type).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) :
type.flags & TypeFlags.Intersection ? getUnionType(map((<IntersectionType>type).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) :
type.flags & TypeFlags.InstantiableNonPrimitive || isGenericTupleType(type) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type, stringsOnly) :
type.flags & TypeFlags.InstantiableNonPrimitive || isGenericTupleType(type) || isGenericMappedType(type) && isNonDistributiveNameType(getNameTypeFromMappedType(type)) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type, stringsOnly) :
getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(<MappedType>type, noIndexSignatures) :
type === wildcardType ? wildcardType :
type.flags & TypeFlags.Unknown ? neverType :