@@ -15332,6 +15332,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1533215332 undefined;
1533315333 }
1533415334 if (t.flags & TypeFlags.Index) {
15335+ if (isGenericMappedType((t as IndexType).type)) {
15336+ const mappedType = (t as IndexType).type as MappedType;
15337+ if (getNameTypeFromMappedType(mappedType) && !isMappedTypeWithKeyofConstraintDeclaration(mappedType)) {
15338+ return getBaseConstraint(getIndexTypeForMappedType(mappedType, IndexFlags.None));
15339+ }
15340+ }
1533515341 return stringNumberSymbolType;
1533615342 }
1533715343 if (t.flags & TypeFlags.TemplateLiteral) {
@@ -18824,7 +18830,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1882418830 // a circular definition. For this reason, we only eagerly manifest the keys if the constraint is non-generic.
1882518831 if (isGenericIndexType(constraintType)) {
1882618832 if (isMappedTypeWithKeyofConstraintDeclaration(type)) {
18827- // We have a generic index and a homomorphic mapping (but a distributive key remapping) - we need to defer
18833+ // We have a generic index and a homomorphic mapping and a key remapping - we need to defer
1882818834 // the whole `keyof whatever` for later since it's not safe to resolve the shape of modifier type.
1882918835 return getIndexTypeForGenericType(type, indexFlags);
1883018836 }
@@ -18854,25 +18860,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1885418860 }
1885518861 }
1885618862
18857- // 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
18858- // 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
18859- // want to perform the reduction when the name type of a mapped type is distributive with respect to the type variable
18860- // introduced by the 'in' clause of the mapped type. Note that non-generic types are considered to be distributive because
18861- // they're the same type regardless of what's being distributed over.
18862- function hasDistributiveNameType(mappedType: MappedType) {
18863- const typeVariable = getTypeParameterFromMappedType(mappedType);
18864- return isDistributive(getNameTypeFromMappedType(mappedType) || typeVariable);
18865- function isDistributive(type: Type): boolean {
18866- return type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Primitive | TypeFlags.Never | TypeFlags.TypeParameter | TypeFlags.Object | TypeFlags.NonPrimitive) ? true :
18867- type.flags & TypeFlags.Conditional ? (type as ConditionalType).root.isDistributive && (type as ConditionalType).checkType === typeVariable :
18868- type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) ? every((type as UnionOrIntersectionType | TemplateLiteralType).types, isDistributive) :
18869- type.flags & TypeFlags.IndexedAccess ? isDistributive((type as IndexedAccessType).objectType) && isDistributive((type as IndexedAccessType).indexType) :
18870- type.flags & TypeFlags.Substitution ? isDistributive((type as SubstitutionType).baseType) && isDistributive((type as SubstitutionType).constraint) :
18871- type.flags & TypeFlags.StringMapping ? isDistributive((type as StringMappingType).type) :
18872- false;
18873- }
18874- }
18875-
1887618863 function getLiteralTypeFromPropertyName(name: PropertyName | JsxAttributeName) {
1887718864 if (isPrivateIdentifier(name)) {
1887818865 return neverType;
@@ -18924,7 +18911,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1892418911 function shouldDeferIndexType(type: Type, indexFlags = IndexFlags.None) {
1892518912 return !!(type.flags & TypeFlags.InstantiableNonPrimitive ||
1892618913 isGenericTupleType(type) ||
18927- isGenericMappedType(type) && (!hasDistributiveNameType( type) || getMappedTypeNameTypeKind(type) === MappedTypeNameTypeKind.Remapping ) ||
18914+ isGenericMappedType(type) && getNameTypeFromMappedType( type) ||
1892818915 type.flags & TypeFlags.Union && !(indexFlags & IndexFlags.NoReducibleCheck) && isGenericReducibleType(type) ||
1892918916 type.flags & TypeFlags.Intersection && maybeTypeOfKind(type, TypeFlags.Instantiable) && some((type as IntersectionType).types, isEmptyAnonymousObjectType));
1893018917 }
@@ -19445,6 +19432,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1944519432 function getSimplifiedType(type: Type, writing: boolean): Type {
1944619433 return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(type as IndexedAccessType, writing) :
1944719434 type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(type as ConditionalType, writing) :
19435+ type.flags & TypeFlags.Index ? getSimplifiedIndexType(type as IndexType) :
1944819436 type;
1944919437 }
1945019438
@@ -19544,6 +19532,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1954419532 return type;
1954519533 }
1954619534
19535+ function getSimplifiedIndexType(type: IndexType) {
19536+ if (isGenericMappedType(type.type) && getNameTypeFromMappedType(type.type) && !isMappedTypeWithKeyofConstraintDeclaration(type.type)) {
19537+ return getIndexTypeForMappedType(type.type, IndexFlags.None);
19538+ }
19539+ return type;
19540+ }
19541+
1954719542 /**
1954819543 * Invokes union simplification logic to determine if an intersection is considered empty as a union constituent
1954919544 */
@@ -24881,7 +24876,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2488124876
2488224877 function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: (readonly [() => Type, __String])[], related: (source: Type, target: Type) => boolean | Ternary) {
2488324878 const types = target.types;
24884- const include: Ternary[] = types.map(t => t.flags & TypeFlags.Primitive ? Ternary.False : Ternary.True);
24879+ const include: Ternary[] = types.map(t => t.flags & TypeFlags.Primitive || getReducedType(t).flags & TypeFlags.Never ? Ternary.False : Ternary.True);
2488524880 for (const [getDiscriminatingType, propertyName] of discriminators) {
2488624881 // If the remaining target types include at least one with a matching discriminant, eliminate those that
2488724882 // have non-matching discriminants. This ensures that we ignore erroneous discriminators and gradually
@@ -42839,12 +42834,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4283942834 // Check if the index type is assignable to 'keyof T' for the object type.
4284042835 const objectType = (type as IndexedAccessType).objectType;
4284142836 const indexType = (type as IndexedAccessType).indexType;
42842- // skip index type deferral on remapping mapped types
42843- const objectIndexType = isGenericMappedType(objectType) && getMappedTypeNameTypeKind(objectType) === MappedTypeNameTypeKind.Remapping
42844- ? getIndexTypeForMappedType(objectType, IndexFlags.None)
42845- : getIndexType(objectType, IndexFlags.None);
4284642837 const hasNumberIndexInfo = !!getIndexInfoOfType(objectType, numberType);
42847- if (everyType(indexType, t => isTypeAssignableTo(t, objectIndexType ) || hasNumberIndexInfo && isApplicableIndexType(t, numberType))) {
42838+ if (everyType(indexType, t => isTypeAssignableTo(t, getIndexType(objectType, IndexFlags.None) ) || hasNumberIndexInfo && isApplicableIndexType(t, numberType))) {
4284842839 if (
4284942840 accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) &&
4285042841 getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.IncludeReadonly
0 commit comments