-
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
Wrong overload resolution with generics #11343
Comments
TypeScript is not good at preserving templated types (i.e. inferring most general type of polymorphic functions). This is generally a duplicate of #9949. Note that even if you comment out the second overload, the types are still not correct, as the template param creator: (a: {}) => () => {} While the correct one would be: creator: <T>(a: T) => () => T PS: It is somewhat related to FAQ - Generics. Unreferenced generic parameters are a no-no as of now :(. |
I'm not sure I understand. I acknowledge that TypeScript is unable to preserve type argument and the best we can get from The main question is: if TypeScript selects the first matching overload, and the first one actually matches, then why does it selects the second one? |
I see now, yes it does seem odd. |
This behaviour is triggered whenever the return type must be inferred. The following works as expected: declare const f: (x:number) => string;
declare const g: (x:boolean) => number;
const c = compose(f, g) // (a: boolean) => string However if we change declare const f: <T>(x:number) => T;
declare const g: (x:boolean) => number;
const c = compose(f, g) // (arg: any) => {} The above example is logically incorrect, because we can't produce a value of type Your example, however, is a special case, because the given signature of type Enhancer = <S>(creator: Creator<S>) => Creator<S>; However, TypeScript doesn't seem to be able to notice that and doesn't use the argument Onto the question, why does the inferencer try harder when there is no second signature - I don't know, but the inferred type is not more useful. If template types were preserved, then from the inferencer's point of view Edit: removed identity observations, because they are not pertinent to the real type of |
Our use case is creating Redux Store: interface Store<S> {
getState(): S;
// bunch of other methods
} And actually the signature of type Creator<S> = (...params) => Store<S>; I just tried to get the minimal failing example. Enhancer doesn't have to be identity, it may take one creator and produce another that e.g. creates the store, does some behaviour enhancements on it and returns the new one without altering its state type |
looks like a duplicate of #9949 |
Actually a better one to dupe against is #9366 |
TypeScript Version: 1.8.10
Code
Expected behavior:
Should compile with no error.
Actual behavior:
Compiler gives error on the last line:
However if we remove the second oveload of
compose
, everything works fine, which means that the first overload actually matches but for some reason the second one is selected.Also, if we remove type variable from
Enhancer
definition and replace it withstring
, it compiles again.The text was updated successfully, but these errors were encountered: