You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Intersected type variable with a recursive constraint fails to infer #55645
This is very related to the other issue I just created (see here). The underlying problem of this particular example is the same. The inferredType for TConfig fails the compareTypes check in getInferredTypehere. This time there is no excess property errors apparent to the user because the excess properties are satisfied through the intersection.
Despite the problem having the same root cause I think it's worth discussing this separately. The other issue could be closed as design limitation/working as intended but this one feels to me a lot closer to being an actual bug that would be worth fixing.
I guess it makes sense if we consider type arguments as assignments and the argument itself as a completely separate piece. From that PoV, it doesn't matter that the argument would succeed if we had used the "original" inferred type (available in inference candidates) and let it flow to the parameter type of the instantiated~ signature.
I expected TConfig to be roughly inferred as the type of the argument. So whatever got gathered here as the inference candidate ({ entry: "foo"; states: { a: { entry: "bar"; }; }; }).
Based on this late conclusion I don't expect this anymore. Or at least - not with the current model for how type arguments work in regards to this. I find it unfortunate that the final structural check of intersected candidates would succeed in this case and yet the candidate is rejected based on common property check failure against its constraint here. It makes it increasingly challenging to infer a recursive structure like this due to various current limitations.
In a way, I don't even want to inferTConfig here but I'd love to have a way to "capture" the argument's type as-is. Inference seemed like a great tool for the job (it's definitely a very close approximation of what I want) but it turns off the excess property check and that's immensely useful in my case. I figured out some ways to preserve or mimic excess property check in simpler situations but they don't work for recursive structures like this. They also require workarounds and just add unnecessary complexity to my types.
Another example of this need would be the queryOptions helper from @tanstack/react-query:
This is a helper that is needed~ to infer things within those "partial" options (especially the contextual parameter types between dependent properties). Its result i reusable and is later meant to be spread into useQuery - but since useQuery is also inferring things, it's best to use the narrowest possible type for options. When returning what might be used as the constraint of TOptions there it could return many optional properties that could accidentally be used as inference sources by useQuery. Inferring TOptions here:
turns off excess property check (undesirable)
breaks intra-expression inference (smth that could be fixed but it has to be challenging if a scenario like this was not fixed in 4.7 when improvements to that were introduced).
Activity
Andarist commentedon Sep 8, 2023
Perhaps this is a design limitation/working as intended since manual type parameters "suffer" from the same problem in this example:
I guess it makes sense if we consider type arguments as assignments and the argument itself as a completely separate piece. From that PoV, it doesn't matter that the argument would succeed if we had used the "original" inferred type (available in inference candidates) and let it flow to the parameter type of the instantiated~ signature.
RyanCavanaugh commentedon Sep 13, 2023
What is your definition of success here?
Andarist commentedon Sep 13, 2023
I expected
TConfigto be roughly inferred as the type of the argument. So whatever got gathered here as the inference candidate ({ entry: "foo"; states: { a: { entry: "bar"; }; }; }).Based on this late conclusion I don't expect this anymore. Or at least - not with the current model for how type arguments work in regards to this. I find it unfortunate that the final structural check of intersected candidates would succeed in this case and yet the candidate is rejected based on common property check failure against its constraint here. It makes it increasingly challenging to infer a recursive structure like this due to various current limitations.
In a way, I don't even want to infer
TConfighere but I'd love to have a way to "capture" the argument's type as-is. Inference seemed like a great tool for the job (it's definitely a very close approximation of what I want) but it turns off the excess property check and that's immensely useful in my case. I figured out some ways to preserve or mimic excess property check in simpler situations but they don't work for recursive structures like this. They also require workarounds and just add unnecessary complexity to my types.Another example of this need would be the
queryOptionshelper from@tanstack/react-query:This is a helper that is needed~ to infer things within those "partial" options (especially the contextual parameter types between dependent properties). Its result i reusable and is later meant to be spread into
useQuery- but sinceuseQueryis also inferring things, it's best to use the narrowest possible type foroptions. When returning what might be used as the constraint ofTOptionsthere it could return many optional properties that could accidentally be used as inference sources byuseQuery. InferringTOptionshere:Sorry for somewhat offtopic train of thought :P
RyanCavanaugh commentedon Sep 13, 2023
I don't entirely follow tbh, but I'm open to a well-explained PR if that's what you're saying 😅