-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Overload resolution: Choosing the wrong overload when arguments involve generic wrappers #13570
Comments
I believe this example also gets to the crux of the issue: interface A<T> {
_a: T;
}
interface B<T> {
_b: T;
}
type AorB<T> = A<T> | B<T>;
declare function isA1<T>(input: AorB<T>): input is A<T>;
declare function isA2(input: AorB<{}>): input is A<{}>;
declare function overload<T>(fn: (input: AorB<T>) => input is A<T>);
declare function overload<T>(fn: (input: AorB<T>) => boolean);
overload(isA1); // uses 2nd overload
overload(isA2); // uses 1st If only one |
Yes, exactly that. There should be some way to control which overload is "preferred" when both are valid, and I had thought that was order (first matching overload is chosen), but it seems like TypeScript is... I dunno, shortcutting and/or getting lazy too early on these evaluations when you don't hint them. |
related to #9366 |
(this seems a different issue namely #10957)
declare function overload(a: number);
declare function overload(b: string);
interface MyFunction<T> {
(t: T): any
}
declare function wrap<T>(f: MyFunction<T>): MyFunction<T>
const myFunction = wrap(overload);
myFunction('qwerty'); // OK
myFunction(9000); // error TS2345: Argument of type '9000' is not assignable to parameter of type 'string'
declare function wrap<F extends MyFunction<T>, T>(f: F): F
|
Actually, that looks more like a question of higher-kinded types, which is the long-standing issue #1213. |
@krryan I'm no expert but it seems to me the problem is in the overloads being ignored. |
They are, but more fundamentally, TS has no way of passing around something that can go multiple ways like that. When you pass |
Is this the same issue?
Can't even use |
@benneq no this is not the issue. See https://basarat.gitbooks.io/typescript/docs/types/typeGuard.html on how to fix. |
@Erikvv I don't think typeguards are going to help benneq. Note that he's testing Anyway, @benneq, your first sniper doesn't work for a few reasons, but none of them are directly related to this. First, TS doesn't support the notion of “entangled” variables, so a test against one is not going to lead to inferences about another. Second, function overloads do very minimal type checking—the overloads have to be at least theoretically compatible with the primary signature, but they are never checked against the function body to see if that is hope they are being used. |
Both `open` and `openReadStream` have overloads, so `promisify` can't know which one to choose and chooses the last one (which doesn't include options). Additionally, once we specify those two overloads, optional args become `arg | undefined` which is subtly different than not providing an arg (which is what we want to be able to do), so we specify onEntry's `openReadStream` callback explicitly as well (to have options be optional). I think this last point is also why we can't just update `yauzl`'s types to have both `options` and `callback` be optional, because `options` when `promisified` will be unioned with `undefined`, not optional (meaning you can't just leave it off, you'd have to actually pass `undefined` as the value if you want to use it). microsoft/TypeScript#13570 microsoft/TypeScript#13195
Both `open` and `openReadStream` have overloads, so `promisify` can't know which one to choose and chooses the last one (which doesn't include options). Additionally, once we specify those two overloads, optional args become `arg | undefined` which is subtly different than not providing an arg (which is what we want to be able to do), so we specify onEntry's `openReadStream` callback explicitly as well (to have options be optional). I think this last point is also why we can't just update `yauzl`'s types to have both `options` and `callback` be optional, because `options` when `promisified` will be unioned with `undefined`, not optional (meaning you can't just leave it off, you'd have to actually pass `undefined` as the value if you want to use it). microsoft/TypeScript#13570 microsoft/TypeScript#13195
Appears to be due to generic inference not using all overloads, which is a known limitation |
TypeScript Version: 2.2.0-dev.20161221
Code
(also on the Playground)
Expected behavior:
Compiles without error.
Actual behavior:
The first invocation of
filter
,filter(foobars, isFoo).map(foo => foo.foo);
, has an errorProperty 'foo' does not exist on type 'FooBar<{}>'
. The second/less-specific overload offilter
is being selected, even though (as the second invocation shows) the first/more-specific overload is valid, and also despite the fact (as shown by the third invocation) the correct overload is chosen when the inferred type does not involve a generic.The text was updated successfully, but these errors were encountered: