-
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
Reverse mapped type with a circular type param sometimes not treated as partially inferrable #48798
Comments
@ahejlsberg thoughts on this one? |
The example works as expected if you remove the circular constraint on const createMachine = <TConfig extends object>(
_config: InferNarrowestObject<TConfig>
): void => {}; So, this tells me that the type inferred for |
The goal of this kind of type is to get "access" to the type of the argument and remap it on our own, introduce relations between certain keys etc as the input acts as a schema. In this particular example, I'm restricting I'm not sure if we can conclude here that the inferred type failed to be assignable to the constraint, or maybe it was - but then the question/problem would be why an unassignable type was inferred there. Even if remove some unusual stuff from this repro case then it still leaves me with confusing results: type Config<TGlobal extends { states: unknown }> = {
initial: keyof TGlobal["states"];
states: {
[StateKey in keyof TGlobal["states"]]: {
on?: Record<string, () => string>;
};
};
};
const createMachine = <TConfig extends Config<TConfig>>(
_config: TConfig
): void => {};
createMachine({
initial: 'pending',
states: {
pending: {
on: {
done() { return ''; }, // errors on initial property because the inferred type is Config<unknown>
// done: () => { return ''; }, // just works
// done: () => { return 42 } // errors correctly because the return type doesnt match
},
},
},
}); And if we take a look at one of the mentioned workarounds for the original repro (see here), it is quite surprising that a random~ added property just "fixes" this. If the problem would be in the type then I would expect this extra property to just error in the same way - but according to my debugging session it's just related to how inference is currently implemented in relation to context sensitive functions. Just note that in this repro with an extra property this is still an context sensitive function - the extra property doesn't really change that trait. It just makes the parent object "partially inferrable" and then the inference algorithm is able to proceed further and accept this method there. Note that if I add more types to the |
Setting a milestone to look at this because I’m intrigued, but there is a significant chance I won’t be able to get to it in that timeframe or I won’t find anything actionable. |
@andrewbranch happy to hop on a call if you would be up for it - I've spent a few hours investigating this in the debugger so I have a good understanding of what happens and where. |
Bug Report
🔎 Search Terms
reverse mapped types, circular type, partially inferrable
⏯ Playground Link
Playground link with relevant code
💻 Code
🙁 Actual behavior
Inferred signature is:
🙂 Expected behavior
states: unknown
shouldn't be inferred here, the reverse mapped type should be able to infer an object literal type~. The type param should be inferred as something like:We can simplify the repro a little bit, but it will then yield an error at a different position and I can't verify right now if the underlying issue is exactly the same in this case (although from what it looks like the root cause is super similar):
TS playground without conditional type applied at the argument position
Note that we can fix both playground by using an arrow function instead of a method (probably related to a possible "hidden"
this
type param that makes this context sensitive in the case of a method).The first one can be fixed by adding a dummy property to the object containing a method (this makes the object partially inferrable):
TS playground with a dummy property added
Especially given that a dummy property fixes the problem it looks like a weird design limitations.
What I've learned when debugging this:
checkFunctionExpressionOrObjectLiteralMethod
they returnanyFunctionType
anyFunctionType
hasObjectFlags.NonInferrableType
on ituninstantiatedType
for theon
property of this argument gets computed to{}
(so it's empty~)isPartiallyInferableType
check when resolving the structure of the reverse mapped type, since the object hasObjectFlags.NonInferrableType
on it AND there are no other properties that would be treated as partially inferrableunknown
is returned for thestates
propertyinitial
property to error becausekeyof unknown
isnever
while a workaround is "known" here (we've learned this hard way though)~ the whole thing still has some problems because we can't provide a param type for the arrow functions contained in
on
property because once we add any unannotated params to an arrow function it becomes context-sensitive and results in a similar problem:TS playground with context-sensitive arrow function
Related to #40439
The text was updated successfully, but these errors were encountered: