Closed
Description
TypeScript Version: 2.2.0-dev.20161221
Code
function filter<P extends Q[], Q, R extends Q>(values: P, isR: (value: Q) => value is R): R[];
function filter<R>(values: R[], isValid: (value: R) => boolean): R[];
function filter<P extends Q[], Q, R extends Q>(values: P, isR: (value: Q) => value is R): R[] {
const result: R[] = [];
values.forEach(q => {
if (isR(q)) {
result.push(q);
}
});
return result;
}
interface Foo<T> {
foo: T;
}
interface Bar<T> {
bar: T;
}
type FooBar<T> = Foo<T> | Bar<T>;
const foobars: FooBar<{}>[] = [];
function isFoo<T>(foobar: FooBar<T>): foobar is Foo<T> {
return 'foo' in foobar;
}
filter(foobars, isFoo).map(foo => foo.foo);
filter<FooBar<{}>[], FooBar<{}>, Foo<{}>>(foobars, isFoo).map(foo => foo.foo);
function isFooObject(foobar: FooBar<{}>): foobar is Foo<{}> {
return isFoo(foobar);
}
filter(foobars, isFooObject).map(foo => foo.foo);
(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 error Property 'foo' does not exist on type 'FooBar<{}>'
. The second/less-specific overload of filter
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.