@@ -15344,6 +15344,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1534415344 undefined;
1534515345 }
1534615346 if (t.flags & TypeFlags.Index) {
15347+ if (isGenericMappedType((t as IndexType).type)) {
15348+ const mappedType = (t as IndexType).type as MappedType;
15349+ if (getNameTypeFromMappedType(mappedType) && !isMappedTypeWithKeyofConstraintDeclaration(mappedType)) {
15350+ return getBaseConstraint(getIndexTypeForMappedType(mappedType, IndexFlags.None));
15351+ }
15352+ }
1534715353 return stringNumberSymbolType;
1534815354 }
1534915355 if (t.flags & TypeFlags.TemplateLiteral) {
@@ -18836,7 +18842,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1883618842 // a circular definition. For this reason, we only eagerly manifest the keys if the constraint is non-generic.
1883718843 if (isGenericIndexType(constraintType)) {
1883818844 if (isMappedTypeWithKeyofConstraintDeclaration(type)) {
18839- // We have a generic index and a homomorphic mapping (but a distributive key remapping) - we need to defer
18845+ // We have a generic index and a homomorphic mapping and a key remapping - we need to defer
1884018846 // the whole `keyof whatever` for later since it's not safe to resolve the shape of modifier type.
1884118847 return getIndexTypeForGenericType(type, indexFlags);
1884218848 }
@@ -18866,25 +18872,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1886618872 }
1886718873 }
1886818874
18869- // 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
18870- // that N distributes over union types, i.e. that N<A | B | C> is equivalent to N<A> | N<B> | N<C>. Specifically, we only
18871- // want to perform the reduction when the name type of a mapped type is distributive with respect to the type variable
18872- // introduced by the 'in' clause of the mapped type. Note that non-generic types are considered to be distributive because
18873- // they're the same type regardless of what's being distributed over.
18874- function hasDistributiveNameType(mappedType: MappedType) {
18875- const typeVariable = getTypeParameterFromMappedType(mappedType);
18876- return isDistributive(getNameTypeFromMappedType(mappedType) || typeVariable);
18877- function isDistributive(type: Type): boolean {
18878- return type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Primitive | TypeFlags.Never | TypeFlags.TypeParameter | TypeFlags.Object | TypeFlags.NonPrimitive) ? true :
18879- type.flags & TypeFlags.Conditional ? (type as ConditionalType).root.isDistributive && (type as ConditionalType).checkType === typeVariable :
18880- type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) ? every((type as UnionOrIntersectionType | TemplateLiteralType).types, isDistributive) :
18881- type.flags & TypeFlags.IndexedAccess ? isDistributive((type as IndexedAccessType).objectType) && isDistributive((type as IndexedAccessType).indexType) :
18882- type.flags & TypeFlags.Substitution ? isDistributive((type as SubstitutionType).baseType) && isDistributive((type as SubstitutionType).constraint) :
18883- type.flags & TypeFlags.StringMapping ? isDistributive((type as StringMappingType).type) :
18884- false;
18885- }
18886- }
18887-
1888818875 function getLiteralTypeFromPropertyName(name: PropertyName | JsxAttributeName) {
1888918876 if (isPrivateIdentifier(name)) {
1889018877 return neverType;
@@ -18936,7 +18923,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1893618923 function shouldDeferIndexType(type: Type, indexFlags = IndexFlags.None) {
1893718924 return !!(type.flags & TypeFlags.InstantiableNonPrimitive ||
1893818925 isGenericTupleType(type) ||
18939- isGenericMappedType(type) && (!hasDistributiveNameType( type) || getMappedTypeNameTypeKind(type) === MappedTypeNameTypeKind.Remapping ) ||
18926+ isGenericMappedType(type) && getNameTypeFromMappedType( type) ||
1894018927 type.flags & TypeFlags.Union && !(indexFlags & IndexFlags.NoReducibleCheck) && isGenericReducibleType(type) ||
1894118928 type.flags & TypeFlags.Intersection && maybeTypeOfKind(type, TypeFlags.Instantiable) && some((type as IntersectionType).types, isEmptyAnonymousObjectType));
1894218929 }
@@ -19457,6 +19444,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1945719444 function getSimplifiedType(type: Type, writing: boolean): Type {
1945819445 return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(type as IndexedAccessType, writing) :
1945919446 type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(type as ConditionalType, writing) :
19447+ type.flags & TypeFlags.Index ? getSimplifiedIndexType(type as IndexType) :
1946019448 type;
1946119449 }
1946219450
@@ -19556,6 +19544,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1955619544 return type;
1955719545 }
1955819546
19547+ function getSimplifiedIndexType(type: IndexType) {
19548+ if (isGenericMappedType(type.type) && getNameTypeFromMappedType(type.type) && !isMappedTypeWithKeyofConstraintDeclaration(type.type)) {
19549+ return getIndexTypeForMappedType(type.type, IndexFlags.None);
19550+ }
19551+ return type;
19552+ }
19553+
1955919554 /**
1956019555 * Invokes union simplification logic to determine if an intersection is considered empty as a union constituent
1956119556 */
@@ -42851,12 +42846,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4285142846 // Check if the index type is assignable to 'keyof T' for the object type.
4285242847 const objectType = (type as IndexedAccessType).objectType;
4285342848 const indexType = (type as IndexedAccessType).indexType;
42854- // skip index type deferral on remapping mapped types
42855- const objectIndexType = isGenericMappedType(objectType) && getMappedTypeNameTypeKind(objectType) === MappedTypeNameTypeKind.Remapping
42856- ? getIndexTypeForMappedType(objectType, IndexFlags.None)
42857- : getIndexType(objectType, IndexFlags.None);
4285842849 const hasNumberIndexInfo = !!getIndexInfoOfType(objectType, numberType);
42859- if (everyType(indexType, t => isTypeAssignableTo(t, objectIndexType ) || hasNumberIndexInfo && isApplicableIndexType(t, numberType))) {
42850+ if (everyType(indexType, t => isTypeAssignableTo(t, getIndexType(objectType, IndexFlags.None) ) || hasNumberIndexInfo && isApplicableIndexType(t, numberType))) {
4286042851 if (
4286142852 accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) &&
4286242853 getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.IncludeReadonly
0 commit comments