Skip to content
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 Signature Is Not Compatible For Inherited Type Function Parameter #17162

Closed
daryllabar opened this issue Jul 13, 2017 · 5 comments
Closed
Labels
Question An issue which isn't directly actionable in code

Comments

@daryllabar
Copy link

TypeScript Version: 2.4.1

Code

// A *self-contained* demonstration of the problem follows...
class Animal {
    a: string;
}

class Dog extends Animal {
    b: string;
}

function test(func: (p: Dog) => any): any;
function test(func: (p: Animal) => any): any;
function test(func: (p: Animal) => any): any {

    return undefined;
}

Expected behavior:
No TS2394 Compiler error

Actual behavior:
a TS2394 Compiler error for this line:

function test(func: (p: Dog) => any): any;

Changing function definition the below resolves the compile error:

function test(func: (p: any) => any): any {
@jcalz
Copy link
Contributor

jcalz commented Jul 13, 2017

This looks like intended behavior.

Since the func parameter is a callback, TS 2.4 is checking it more strictly than earlier versions.

The type of func in each overload needs to be assignable to the type of the func in the implementation. Or, from the other direction: the type of func in the implementation should be a supertype of all the types declared for func in the overloads.

Let's call (p: Dog) => any a Dog-consumer, and (p: Animal) => any an Animal-consumer. Note that every Animal-consumer is a Dog-consumer (because something that consumes animals will accept a dog), but not every Dog-consumer is an Animal-consumer (because something that consumes dogs might not accept, say, a cat). That means that Dog-consumer is a supertype of Animal-consumer. Since one overload takes a Dog-consumer, and the other takes an Animal-consumer, the implementation should take a supertype of these: Dog-consumer.

That is:

function test(func: (p: Dog) => any): any;
function test(func: (p: Animal) => any): any;
function test(func: (p: Dog) => any): any {  // no error now

@daryllabar
Copy link
Author

daryllabar commented Jul 13, 2017

Ahh, so I confused a "callback parameter" with the return type. Since func is a call back function, it's type is a call back parameter?

Side note, I would expect this to give a different error

function test(func: (p: Dog) => any): any;
function test(func: (p: Animal) => any): any;
function test(func: (p: Animal|Dog) => any): any {

because func: (p:Animal) doesn't accept a Dog.

Never-mind, it's the same issue and I see that now. This is what I want:

function test(func: (p: Dog) => any): any;
function test(func: (p: Animal) => any): any;
function test(func: ((p: Animal) => any) | ((p:Dog) => any)): any {

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Jul 13, 2017
@jcalz
Copy link
Contributor

jcalz commented Jul 13, 2017

Note that func: ((p: Animal) => any) | ((p:Dog) => any) is essentially equivalent to func: ((p:Dog) => any). If you use the union, you'll find that you can't actually call func() on anything directly (see #14107), so the latter is probably preferable.

@daryllabar
Copy link
Author

@jcalz I noticed that. Ended up with something like this:

function test<T,A extends Dog   >(animal:A, func: (p: A) => T): T;
function test<T,A extends Animal>(animal:A, func: (p: A) => Foo<T>): Foo<T>;
function test<T,A extends Animal>(animal:A, func: (p: A) => T|Foo<T>): T|Foo<T> {
    return func(animal);
}

I've included Foo<T> just so it would make sense as to why the overload would be defined

I'm guessing that is the best way?

@RyanCavanaugh
Copy link
Member

@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

3 participants