-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Defer index types on remapping mapped types #55140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
a59d618
b4593fd
8407df6
f7c7417
f6b0c86
9c88462
9f95520
847cb6d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1295,6 +1295,12 @@ const enum MappedTypeModifiers { | |
| ExcludeOptional = 1 << 3, | ||
| } | ||
|
|
||
| const enum MappedTypeNameTypeKind { | ||
| None = 0, | ||
| Filtering = 1 << 0, | ||
| Remapping = 1 << 1, | ||
| } | ||
|
|
||
| const enum ExpandingFlags { | ||
| None = 0, | ||
| Source = 1, | ||
|
|
@@ -13224,7 +13230,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
| const constraintType = getConstraintTypeFromMappedType(type); | ||
| const mappedType = (type.target as MappedType) || type; | ||
| const nameType = getNameTypeFromMappedType(mappedType); | ||
| const shouldLinkPropDeclarations = !nameType || isFilteringMappedType(mappedType); | ||
| const shouldLinkPropDeclarations = !(getMappedTypeNameTypeKind(mappedType) & MappedTypeNameTypeKind.Remapping); | ||
| const templateType = getTemplateTypeFromMappedType(mappedType); | ||
| const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T' | ||
| const templateModifiers = getMappedTypeModifiers(type); | ||
|
|
@@ -13404,9 +13410,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
| return false; | ||
| } | ||
|
|
||
| function isFilteringMappedType(type: MappedType): boolean { | ||
| function getMappedTypeNameTypeKind(type: MappedType): MappedTypeNameTypeKind { | ||
| const nameType = getNameTypeFromMappedType(type); | ||
| return !!nameType && isTypeAssignableTo(nameType, getTypeParameterFromMappedType(type)); | ||
| if (!nameType) { | ||
| return MappedTypeNameTypeKind.None; | ||
| } | ||
| return isTypeAssignableTo(nameType, getTypeParameterFromMappedType(type)) ? MappedTypeNameTypeKind.Filtering : MappedTypeNameTypeKind.Remapping; | ||
| } | ||
|
|
||
| function resolveStructuredTypeMembers(type: StructuredType): ResolvedType { | ||
|
|
@@ -17075,7 +17084,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
| function shouldDeferIndexType(type: Type, indexFlags = IndexFlags.None) { | ||
| return !!(type.flags & TypeFlags.InstantiableNonPrimitive || | ||
| isGenericTupleType(type) || | ||
| isGenericMappedType(type) && !hasDistributiveNameType(type) || | ||
| isGenericMappedType(type) && (!hasDistributiveNameType(type) || !(indexFlags & IndexFlags.NoRemappingMappedTypeDeferral) && getMappedTypeNameTypeKind(type) & MappedTypeNameTypeKind.Remapping) || | ||
| type.flags & TypeFlags.Union && !(indexFlags & IndexFlags.NoReducibleCheck) && isGenericReducibleType(type) || | ||
| type.flags & TypeFlags.Intersection && maybeTypeOfKind(type, TypeFlags.Instantiable) && some((type as IntersectionType).types, isEmptyAnonymousObjectType)); | ||
| } | ||
|
|
@@ -17632,7 +17641,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
| // K is generic and N is assignable to P, instantiate E using a mapper that substitutes the index type for P. | ||
| // For example, for an index access { [P in K]: Box<T[P]> }[X], we construct the type Box<T[X]>. | ||
| if (isGenericMappedType(objectType)) { | ||
| if (!getNameTypeFromMappedType(objectType) || isFilteringMappedType(objectType)) { | ||
| if (!(getMappedTypeNameTypeKind(objectType) & MappedTypeNameTypeKind.Remapping)) { | ||
| return type[cache] = mapType(substituteIndexedMappedType(objectType, type.indexType), t => getSimplifiedType(t, writing)); | ||
| } | ||
| } | ||
|
|
@@ -38913,7 +38922,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
| // Check if the index type is assignable to 'keyof T' for the object type. | ||
| const objectType = (type as IndexedAccessType).objectType; | ||
| const indexType = (type as IndexedAccessType).indexType; | ||
| if (isTypeAssignableTo(indexType, getIndexType(objectType, IndexFlags.None))) { | ||
| if (isTypeAssignableTo(indexType, getIndexType(objectType, IndexFlags.NoRemappingMappedTypeDeferral))) { | ||
|
||
| if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) && | ||
| getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.IncludeReadonly) { | ||
| error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType)); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a flags enum? I can't see anywhere we actually combine multiple flags - in fact, it seems to me like a mapped type can only be one, given the implementation of
getMappedTypeNameTypeKind.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had some composite values here before but removed them at the end since I didn't actually use them anywhere. Refactored this now to be a non-flag enum