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
Callback parameter inference not working when part of an inferred tuple type #52047
Been experiencing the below problem with no-implicit-any on callback parameter types, when the callback is part of a tuple function-argument, whose type I am inferring.
Was thinking it could be a case of unsupported/incorrect usage on my end, however the type suggestion does appear to be correct on-mouse-hover, so wondering if there's something extra at play.
This is the behavior in every version I tried since 4.0 that brought support for variadic tuples, and I reviewed the FAQ for entries about generics/tuples/callbacks
(for context, if the above example feels a bit contrived: the actual use-case involves typing/checking a function argument that can be a variadic tuple with multiple complex elements, using a more complex utility type. If interested here's a second playground link with the whole shebang - but in the first one I've tried to pare it down to the most basic example with just 1 element on the tuple)
💻 Code
typeOptions<T=unknown>={inputData: T;handler: (t: T)=>void}typeElemOptions<T>=Textends{inputData: infer X} ? Options<X> : nevertypeTupleOptions<Textendsany[],>=Textends[infer Elem]
? [ElemOptions<Elem>]
: TfunctionfooWithTuple<Textendsany[]>(bar: readonly[...TupleOptions<T>]){return}fooWithTuple([{inputData: 'string',// Error: Parameter 'x' implicitly has an 'any' type.// even though hovering over `handler` correctly labels it as `handler: (t: string) => void`handler: (x)=>{}}])// included in the playground link but not shown here:// (1) type-inference all works fine when you're not dealing with a tuple, and// (2) type-checking in a tuple works correctly when you add the param type explicitly
🙁 Actual behavior
Handler complains about no-implicit-any, even though type-suggestion work as expected, and type-checking works if you add the param type explicitly.
🙂 Expected behavior
Handler parameter type can be inferred automatically; no no-implicit-any complaints.
You can implement this one with reverse mapped types: TS playground
Discussed a bit in an external thread - mapped types may not work for the use case where each element in the tuple has multiple type parameters to infer (updated the second playground link in the issue description to reflect this example)
As mentioned in that other thread - I strongly believe that this proposal would make it way easier to implement such types. With that in place, we could reuse the "reverse mapped types" technique presented in the playground above to infer multiple "generics" per tuple element (where each "generic" would just be a property of the inferred element).
This one will be extremely hard to fix for outside contributors without a deep understanding of the internals of inference, contextual typing, etc.
The problem is that a source object with context-sensitive functions starts as a NonInferrableType. Nothing can be inferred from it so it falls back to the constraint and that's just any[] here. The function's parameters are assigned from within checkExpressionWithContextualType based on the contextualSignature - but there is none since it couldn't infer anything so far as the source was "non-inferrable" and so it is forced to assign any to those parameters and it can never come back to this place in an attempt to reassign them (likely because other inferences that are made after that could depend on this assigned information).
Fixing this would require the compiler to become smarter about "partially inferrable types". I actually managed to fix this locally but, as I expected, the anyFunctionType appeared in the output of some tests where it shouldn't (it "leaked"). I think that perhaps it would be possible to allow those partially inferrable types to propagate as inference candidates a little bit but the compiler would have to know when and how to discard them if needed (or something like that).
It's actually interesting here that reverse-mapped types can infer from partially inferrable types (isPartiallyInferableType is literally only used by createReverseMappedType). So they could be a viable alternative here but for them to be usable by Arty (@artysidorenko)'s use case (which isn't presented by this issue here in full) some improvements for reverse mapped types would have to be made: #52095 #53017 (this isn't strictly required to satisfy the use case but it would allow to type this stuff in an easier way, the alternative to this is inferring to interested reverse mapped types and that's not as readable) #52062 (#52095 is a more general take on improvements to getTypeOfPropertyOfContextualType and it - almost - eliminates the need for this PR, the only added benefit of this PR over #52062 is an extra fix targeted at tuples) #54029
Activity
Andarist commentedon Dec 29, 2022
You can implement this one with reverse mapped types: TS playground
artysidorenko commentedon Dec 31, 2022
Discussed a bit in an external thread - mapped types may not work for the use case where each element in the tuple has multiple type parameters to infer (updated the second playground link in the issue description to reflect this example)
Andarist commentedon Dec 31, 2022
As mentioned in that other thread - I strongly believe that this proposal would make it way easier to implement such types. With that in place, we could reuse the "reverse mapped types" technique presented in the playground above to infer multiple "generics" per tuple element (where each "generic" would just be a property of the inferred element).
Andarist commentedon May 12, 2023
This one will be extremely hard to fix for outside contributors without a deep understanding of the internals of inference, contextual typing, etc.
The problem is that a source object with context-sensitive functions starts as a
NonInferrableType. Nothing can be inferred from it so it falls back to the constraint and that's justany[]here. The function's parameters are assigned from withincheckExpressionWithContextualTypebased on thecontextualSignature- but there is none since it couldn't infer anything so far as the source was "non-inferrable" and so it is forced to assignanyto those parameters and it can never come back to this place in an attempt to reassign them (likely because other inferences that are made after that could depend on this assigned information).Fixing this would require the compiler to become smarter about "partially inferrable types". I actually managed to fix this locally but, as I expected, the
anyFunctionTypeappeared in the output of some tests where it shouldn't (it "leaked"). I think that perhaps it would be possible to allow those partially inferrable types to propagate as inference candidates a little bit but the compiler would have to know when and how to discard them if needed (or something like that).It's actually interesting here that reverse-mapped types can infer from partially inferrable types (
isPartiallyInferableTypeis literally only used bycreateReverseMappedType). So they could be a viable alternative here but for them to be usable by Arty (@artysidorenko)'s use case (which isn't presented by this issue here in full) some improvements for reverse mapped types would have to be made:#52095
#53017 (this isn't strictly required to satisfy the use case but it would allow to type this stuff in an easier way, the alternative to this is inferring to interested reverse mapped types and that's not as readable)
#52062 (#52095 is a more general take on improvements to
getTypeOfPropertyOfContextualTypeand it - almost - eliminates the need for this PR, the only added benefit of this PR over #52062 is an extra fix targeted at tuples)#54029