-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
bugfix: homomorphic mapped types when T is non-generic, solves 27995 #48433
base: main
Are you sure you want to change the base?
Conversation
8dad1d4
to
260708d
Compare
… mapped tuple type
src/compiler/checker.ts
Outdated
@@ -15848,6 +15859,19 @@ namespace ts { | |||
// Eagerly resolve the constraint type which forces an error if the constraint type circularly | |||
// references itself through one or more type aliases. | |||
getConstraintTypeFromMappedType(type); |
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.
do you perhaps understand why this isn't sort of handled within getConstraintTypeFromMappedType
? I recall we were trying to investigate that
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.
So getConstraintTypeFromMappedType
is delegating to getConstraintOfTypeParameter
the job of getting the constraint type and additionaly sets it in the mapped type, here I have 2 choices either extend getConstraintTypeFromMappedType
to detect the condition and eventually mutate the constraint
of the type parameter or to extend the logic of getConstraintOfTypeParameter
to check if the constraint is for a homomorphic mapped type. The function getConstraintOfTypeParameter
is also directly invoked when checking index expressions like A[k]
where getConstraintTypeFromMappedType
isn't, the function returns the already resolved constraint if there so in theory it could still work but I felt more appropriate to have this logic in getConstraintOfTypeParameter
as the lowest common
src/compiler/checker.ts
Outdated
const constraintType = getConstraintTypeFromMappedType(type); | ||
checkTypeAssignableTo(constraintType, keyofConstraintType, getEffectiveConstraintOfTypeParameter(node.typeParameter)); | ||
const type = getTypeFromMappedTypeNode(node); | ||
// Continue to check if the type returned is a mapped type, that means it wasn't resolved to a homomorphic tuple type |
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.
where does this typechecking for a homomorphic mapped type happen now? in the added instantiateMappedTupleType
call?
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.
So in case the returned type is a tuple type (which I now realize it may be a simpler condition here) we don't have a mapped type to check, one condition is implicitly checked, as the type can only be homomorphic if it has no nameType (the AS rest
component of the type parameter) the other on assignability of the constraint to the keyOfConstraintType should be once again implicit given the constraint is the keyof of a tuple BUT I may be wrong :)
Looking at the last comment here it also might fix the issue there |
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 think a maybe more consistent approach would be changing how getTypeFromMappedTypeNode
constructs the type to align more with how instantiateMappedType
behaves - ideally sharing some functionality between the two. The current approach feels a bit ad-hoc, and I don't particularly like trafficking around all this information as part of the constraint logic for the mapped type. If {[K in keyof MyTuple]: MyTuple[K] | string}
is just supposed to do the mapping immediately and make a tuple type reference, then that's just what we should do when we get the type from the type node - we should skip out on making the mapped type object entirely.
@weswigham I pushed out the requested changes - to some extent at least. I'm not really sure if this was worth it though. The parameters list change of Let me know what you think. |
Took a stab at it, the way I've approached is detecting if
T
in a{ [k in keyof T]: F<T> }
is a tuple type and in case it is resolve the node to an instantiated tuple type.I am not sure if this covers all the cases or if it ends up breaking anything else, please let me know if I should change something
Fixes #27995
cc @Andarist
--
This only deals with tuple, if the way to do it is correct I'd be happy to extend it to mapped arrays too.