Skip to content

Improper type inferred in presence of overloads #10957

Description

@evmar

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.)

Activity

  1. evmar commented on Sep 20, 2016

    @evmar
    ContributorAuthor

    This example from Rado Kirov (@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'.
    
  2. added
    Needs InvestigationThis issue needs a team member to investigate its status.
    and removed
    Needs InvestigationThis issue needs a team member to investigate its status.
    on May 24, 2017
  3. Erikvv commented on Aug 17, 2018

    @Erikvv

    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>
  4. added
    QuestionAn issue which isn't directly actionable in code
    and removed
    Needs InvestigationThis issue needs a team member to investigate its status.
    on Aug 23, 2019
  5. RyanCavanaugh commented on Aug 23, 2019

    @RyanCavanaugh
    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;
    }
  6. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionAn issue which isn't directly actionable in code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions