Skip to content

Commit 5fb6593

Browse files
committed
Distribute mapped types over array/tuple intersections
1 parent 3e91592 commit 5fb6593

File tree

1 file changed

+29
-24
lines changed

1 file changed

+29
-24
lines changed

Diff for: src/compiler/checker.ts

+29-24
Original file line numberDiff line numberDiff line change
@@ -14569,14 +14569,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1456914569
const constraint = getConstraintTypeFromMappedType(type);
1457014570
if (constraint.flags & TypeFlags.Index) {
1457114571
const baseConstraint = getBaseConstraintOfType((constraint as IndexType).type);
14572-
if (baseConstraint && everyType(baseConstraint, isArrayOrTupleType)) {
14572+
if (baseConstraint && everyType(baseConstraint, t => isArrayOrTupleType(t) || isArrayOrTupleOrIntersection(t))) {
1457314573
return instantiateType(target, prependTypeMapping(typeVariable, baseConstraint, type.mapper));
1457414574
}
1457514575
}
1457614576
}
1457714577
return type;
1457814578
}
1457914579

14580+
function isArrayOrTupleOrIntersection(type: Type) {
14581+
return !!(type.flags & TypeFlags.Intersection) && every((type as IntersectionType).types, isArrayOrTupleType);
14582+
}
14583+
1458014584
function isMappedTypeGenericIndexedAccess(type: Type) {
1458114585
let objectType;
1458214586
return !!(type.flags & TypeFlags.IndexedAccess && getObjectFlags(objectType = (type as IndexedAccessType).objectType) & ObjectFlags.Mapped &&
@@ -19767,6 +19771,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1976719771
// * If T is a union type we distribute the mapped type over the union.
1976819772
// * If T is an array we map to an array where the element type has been transformed.
1976919773
// * If T is a tuple we map to a tuple where the element types have been transformed.
19774+
// * If T is an intersection of array or tuple types we map to an intersection of transformed array or tuple types.
1977019775
// * Otherwise we map to an object type where the type of each property has been transformed.
1977119776
// For example, when T is instantiated to a union type A | B, we produce { [P in keyof A]: X } |
1977219777
// { [P in keyof B]: X }, and when when T is instantiated to a union type A | undefined, we produce
@@ -19775,33 +19780,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1977519780
if (typeVariable) {
1977619781
const mappedTypeVariable = instantiateType(typeVariable, mapper);
1977719782
if (typeVariable !== mappedTypeVariable) {
19778-
return mapTypeWithAlias(
19779-
getReducedType(mappedTypeVariable),
19780-
t => {
19781-
if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType && !isErrorType(t)) {
19782-
if (!type.declaration.nameType) {
19783-
let constraint;
19784-
if (
19785-
isArrayType(t) || t.flags & TypeFlags.Any && findResolutionCycleStartIndex(typeVariable, TypeSystemPropertyName.ImmediateBaseConstraint) < 0 &&
19786-
(constraint = getConstraintOfTypeParameter(typeVariable)) && everyType(constraint, isArrayOrTupleType)
19787-
) {
19788-
return instantiateMappedArrayType(t, type, prependTypeMapping(typeVariable, t, mapper));
19789-
}
19790-
if (isTupleType(t)) {
19791-
return instantiateMappedTupleType(t, type, typeVariable, mapper);
19792-
}
19793-
}
19794-
return instantiateAnonymousType(type, prependTypeMapping(typeVariable, t, mapper));
19795-
}
19796-
return t;
19797-
},
19798-
aliasSymbol,
19799-
aliasTypeArguments,
19800-
);
19783+
return mapTypeWithAlias(getReducedType(mappedTypeVariable), instantiateConstituent, aliasSymbol, aliasTypeArguments);
1980119784
}
1980219785
}
1980319786
// If the constraint type of the instantiation is the wildcard type, return the wildcard type.
1980419787
return instantiateType(getConstraintTypeFromMappedType(type), mapper) === wildcardType ? wildcardType : instantiateAnonymousType(type, mapper, aliasSymbol, aliasTypeArguments);
19788+
19789+
function instantiateConstituent(t: Type): Type {
19790+
if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType && !isErrorType(t)) {
19791+
if (!type.declaration.nameType) {
19792+
let constraint;
19793+
if (
19794+
isArrayType(t) || t.flags & TypeFlags.Any && findResolutionCycleStartIndex(typeVariable!, TypeSystemPropertyName.ImmediateBaseConstraint) < 0 &&
19795+
(constraint = getConstraintOfTypeParameter(typeVariable!)) && everyType(constraint, isArrayOrTupleType)
19796+
) {
19797+
return instantiateMappedArrayType(t, type, prependTypeMapping(typeVariable!, t, mapper));
19798+
}
19799+
if (isTupleType(t)) {
19800+
return instantiateMappedTupleType(t, type, typeVariable!, mapper);
19801+
}
19802+
if (isArrayOrTupleOrIntersection(t)) {
19803+
return getIntersectionType(map((t as IntersectionType).types, instantiateConstituent));
19804+
}
19805+
}
19806+
return instantiateAnonymousType(type, prependTypeMapping(typeVariable!, t, mapper));
19807+
}
19808+
return t;
19809+
}
1980519810
}
1980619811

1980719812
function getModifiedReadonlyState(state: boolean, modifiers: MappedTypeModifiers) {

0 commit comments

Comments
 (0)