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

Improper type inferred in presence of overloads #10957

Closed
evmar opened this issue Sep 16, 2016 · 3 comments
Closed

Improper type inferred in presence of overloads #10957

evmar opened this issue Sep 16, 2016 · 3 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@evmar
Copy link
Contributor

evmar commented Sep 16, 2016

TypeScript Version: 2.1.0-dev.20160916

Code

interface Editor {
  on(e: string, h: (x: Editor) => void): void;
  on(e: string, h: (x: string, e: any) => void): void;
  on(e: 'foo', h: (x: Editor, e: any) => void): void;
}

let cm: Editor = null as any;
cm.on('bar', (x, y) => {});

Expected behavior:

cm.on() infers some type for its second param that is accepted by the compiler, given that the param has no types specified.

Actual behavior:

err.ts(8,14): error TS2345: Argument of type '(x: Editor, y: any) => void' is not assignable to parameter of type '(x: string, e: any) => void'.
  Types of parameters 'x' and 'x' are incompatible.
    Type 'string' is not assignable to type 'Editor'.

It appears to infer that its param should have the third overload's expected type, but then typechecks it against the second overload.

It appears to also be sensitive to the order in which the overloads are declared.

(This is reduced from a larger example that involves the CodeMirror d.ts files.)

@evmar
Copy link
Contributor Author

evmar commented Sep 20, 2016

This example from @rkirov is a bit smaller and has maybe the same error.

interface Editor {
  on(h: (x: boolean) => void): void;
  on(h: (x: string, e: string) => void): void;
}

let cm: Editor = null as any;
cm.on((x, y) => {});
Argument of type '(x: boolean, y: any) => void' is not assignable to parameter of type '(x: string, e: string) => void'.
  Types of parameters 'x' and 'x' are incompatible.
    Type 'string' is not assignable to type 'boolean'.

@RyanCavanaugh RyanCavanaugh added Needs Investigation This issue needs a team member to investigate its status. and removed Needs Investigation This issue needs a team member to investigate its status. labels May 24, 2017
@Erikvv
Copy link

Erikvv commented Aug 17, 2018

I ran into this and I found out that if you replace the overload by an equivalent Union type it works! Though an overloaded function seems to me an intersection type but that doesn't work.

This is maybe not so hard to fix so I hope the typescript team can give this some prio.

Faulty behavior in the case of overloads:

interface MyFunction1 {
  (): string
  (): number
}

// should be string|number but actually is number
type StringOrNumber1 = ReturnType<MyFunction1> 

Correct behaviour in the case of Union types:

type MyFunction2 = 
    (() => string) 
    | 
    (() => number)

// is string|number
type StringOrNumber2 = ReturnType<MyFunction2>

@RyanCavanaugh RyanCavanaugh added Question An issue which isn't directly actionable in code and removed Needs Investigation This issue needs a team member to investigate its status. labels Aug 23, 2019
@RyanCavanaugh
Copy link
Member

The definition in the OP has signatures in the wrong order - callbacks with more parameters should go first:

interface Editor {
  on(e: string, h: (x: string, e: any) => void): void;
  on(e: string, h: (x: Editor) => void): void;
  on(e: 'foo', h: (x: Editor, e: any) => void): void;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

3 participants