Repository navigation
Can't correctly infer generic interface type when it's behind a function #25092
Copy link
Copy link
Closed
Labels
Design LimitationConstraints of the existing architecture prevent this from being fixedConstraints of the existing architecture prevent this from being fixedFix AvailableA PR has been opened for this issueA PR has been opened for this issue
Milestone
Description
TypeScript Version: 2.9
Search Terms:
function parameter inference
Code
interface MyInterface<T> {
retrieveGeneric: (parameter: string) => T,
operateWithGeneric: (generic: T) => string
}
const inferTypeFn = <T>(generic: MyInterface<T>) => generic;
// inferred type for myGeneric = MyInterface<{}>, `generic.toFixed()` marked as error (as {} doesn't have .toFixed())
const myGeneric = inferTypeFn({
retrieveGeneric: parameter => 5,
operateWithGeneric: generic => generic.toFixed()
});
// inferred type for myGeneric = MyInterface<number>, everything OK
const myWorkingGeneric = inferTypeFn({
retrieveGeneric: (parameter: string) => 5,
operateWithGeneric: generic => generic.toFixed()
});Expected behavior:
myGeneric has every type correctly inferred, parameter is a string, generic is a number.
Actual behavior:
it doesn't infer the correct type for generic parameter unless you manually specify the type of parameter (which it already had the right type)
Reacted by Josep M Sobrepere, Vladimir Katushenok, Ferdy Budhidharma, Jonathan Rimmer, csr632, Tom and centigrade-julian-lang
Metadata
Metadata
Assignees
Labels
Design LimitationConstraints of the existing architecture prevent this from being fixedConstraints of the existing architecture prevent this from being fixedFix AvailableA PR has been opened for this issueA PR has been opened for this issue
Activity
donaldpipowitch commentedon Jul 2, 2018
Is this the same issue? Return type is casted to
any, if generic is used:Tested on PlayGround.
otbe commentedon Jul 2, 2018
I wonder if I got the same issue for interfaces + classes. Have a look at this playground.
If you hover over
createHandler(line 15) you will see{}as inferred type instead ofstringYiSiWang commentedon Jul 3, 2018
Andy (Andrewkraft) (@Andy-MS) I got a similar issue and found a solution/workaround:
Hope it helps :) .
Benjamin Otto (@otbe) This works.
otbe commentedon Jul 3, 2018
14 (@YiSiWang) thanks! Never thought swapping the position would change something :)
I wonder if this is bug or works as intended?
weswigham commentedon Sep 10, 2018
Inside the compiler, we have this concepts of something called a contextual type and a context-sensitive function. A contextual type is simply the type a position must have based on what it is being assigned to. A context-sensitive function is a function with untyped function parameters. When a context-sensitive function exists, its type must be derived from the contextual type at that location.
In
both functions in the object literal are context-sensitive. This means we try to solve their types during inference independently. We see
parameterunannotated first, lock in{}as the inference (since we decide thatparametermust have a type before we can check the body), and then that's what it's stuck with.whereas
only
operateWithGenericis context-sensitive. This means we create an inference ofT -> stringbefore we even look at the context sensitive function (since we do context-free inferences and then context-sensitive ones) and everything's good.We're conservative here because we assume that a parameter, if present, may affect the return type of a function. Based on what we've talked about in related issues before, it's unlikely we'll specifically improve this without moving to a full unification-based solve for the arguments. the recommendation right now is to not list parameters you don't use (or if you must list them, manually assign them types). ❤️
sutarmin commentedon Oct 17, 2018
Wesley Wigham (@weswigham) I wonder if following piece of code is related to this issue:
We have type checking here (
(arg: string) => argwon't fit), but don't have type inference.Is it the same problem or something different?
raveclassic commentedon Oct 17, 2018
Might be related #23429, #22715 #15005
I've added a compete example of Anton Sutarmin (@sutarmin) 's problem here
ferdaber commentedon Mar 7, 2019
Wesley Wigham (@weswigham) I should add that this affects JSX as well, with generic components:
RyanCavanaugh commentedon Mar 13, 2019
Tracking at #30134
csr632 commentedon Nov 30, 2019
It will report error when you do this:
This is so wierd.