🤖 Pick PR #57801 (Distribute mapped types over array/...) into release-5.4 (#57832)

Co-authored-by: Anders Hejlsberg <andersh@microsoft.com>
This commit is contained in:
TypeScript Bot
2024-03-18 11:56:40 -07:00
committed by GitHub
parent 609560f36b
commit b45a41823e
4 changed files with 152 additions and 24 deletions

View File

@@ -14557,7 +14557,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const constraint = getConstraintTypeFromMappedType(type);
if (constraint.flags & TypeFlags.Index) {
const baseConstraint = getBaseConstraintOfType((constraint as IndexType).type);
if (baseConstraint && everyType(baseConstraint, isArrayOrTupleType)) {
if (baseConstraint && everyType(baseConstraint, t => isArrayOrTupleType(t) || isArrayOrTupleOrIntersection(t))) {
return instantiateType(target, prependTypeMapping(typeVariable, baseConstraint, type.mapper));
}
}
@@ -14565,6 +14565,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return type;
}
function isArrayOrTupleOrIntersection(type: Type) {
return !!(type.flags & TypeFlags.Intersection) && every((type as IntersectionType).types, isArrayOrTupleType);
}
function isMappedTypeGenericIndexedAccess(type: Type) {
let objectType;
return !!(type.flags & TypeFlags.IndexedAccess && getObjectFlags(objectType = (type as IndexedAccessType).objectType) & ObjectFlags.Mapped &&
@@ -19759,6 +19763,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// * If T is a union type we distribute the mapped type over the union.
// * If T is an array we map to an array where the element type has been transformed.
// * If T is a tuple we map to a tuple where the element types have been transformed.
// * If T is an intersection of array or tuple types we map to an intersection of transformed array or tuple types.
// * Otherwise we map to an object type where the type of each property has been transformed.
// For example, when T is instantiated to a union type A | B, we produce { [P in keyof A]: X } |
// { [P in keyof B]: X }, and when when T is instantiated to a union type A | undefined, we produce
@@ -19767,33 +19772,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (typeVariable) {
const mappedTypeVariable = instantiateType(typeVariable, mapper);
if (typeVariable !== mappedTypeVariable) {
return mapTypeWithAlias(
getReducedType(mappedTypeVariable),
t => {
if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType && !isErrorType(t)) {
if (!type.declaration.nameType) {
let constraint;
if (
isArrayType(t) || t.flags & TypeFlags.Any && findResolutionCycleStartIndex(typeVariable, TypeSystemPropertyName.ImmediateBaseConstraint) < 0 &&
(constraint = getConstraintOfTypeParameter(typeVariable)) && everyType(constraint, isArrayOrTupleType)
) {
return instantiateMappedArrayType(t, type, prependTypeMapping(typeVariable, t, mapper));
}
if (isTupleType(t)) {
return instantiateMappedTupleType(t, type, typeVariable, mapper);
}
}
return instantiateAnonymousType(type, prependTypeMapping(typeVariable, t, mapper));
}
return t;
},
aliasSymbol,
aliasTypeArguments,
);
return mapTypeWithAlias(getReducedType(mappedTypeVariable), instantiateConstituent, aliasSymbol, aliasTypeArguments);
}
}
// If the constraint type of the instantiation is the wildcard type, return the wildcard type.
return instantiateType(getConstraintTypeFromMappedType(type), mapper) === wildcardType ? wildcardType : instantiateAnonymousType(type, mapper, aliasSymbol, aliasTypeArguments);
function instantiateConstituent(t: Type): Type {
if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType && !isErrorType(t)) {
if (!type.declaration.nameType) {
let constraint;
if (
isArrayType(t) || t.flags & TypeFlags.Any && findResolutionCycleStartIndex(typeVariable!, TypeSystemPropertyName.ImmediateBaseConstraint) < 0 &&
(constraint = getConstraintOfTypeParameter(typeVariable!)) && everyType(constraint, isArrayOrTupleType)
) {
return instantiateMappedArrayType(t, type, prependTypeMapping(typeVariable!, t, mapper));
}
if (isTupleType(t)) {
return instantiateMappedTupleType(t, type, typeVariable!, mapper);
}
if (isArrayOrTupleOrIntersection(t)) {
return getIntersectionType(map((t as IntersectionType).types, instantiateConstituent));
}
}
return instantiateAnonymousType(type, prependTypeMapping(typeVariable!, t, mapper));
}
return t;
}
}
function getModifiedReadonlyState(state: boolean, modifiers: MappedTypeModifiers) {