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

Report errors on all plausible overloads #27249

Closed
RyanCavanaugh opened this issue Sep 20, 2018 · 5 comments · Fixed by #32092
Closed

Report errors on all plausible overloads #27249

RyanCavanaugh opened this issue Sep 20, 2018 · 5 comments · Fixed by #32092
Assignees
Labels
Committed The team has roadmapped this issue Suggestion An idea for TypeScript

Comments

@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Sep 20, 2018

TypeScript Version: 3.1

Search Terms: overload all errors

Code

declare function render(s: object, opts: { fileName: string }): void;
declare function render(s: string, name: string): void;

declare const obj: object;
// Actual error: cannot convert 'object' to 'string'
// Desired error: fileName / filename mismatch
render(obj, { filename: "foo" });

When multiple overloads with very different signatures exist, the ordering is effectively arbitrary. This creates really bad error messages when the "last" overload wasn't the one you were trying to call.

While some functions have an extremely large number of overloads, when there are only a few (< 5?) overloads, we should report their failures individually so that hopefully one of the error messages is useful.

e.g. instead of

TS2345: Argument of type 'object' is not assignable to parameter of type 'string'.

it should be

TSXXXX: Failed to find a suitable overload for this call
  When invoking "(s: string, name: stri...":
    TS2345: Argument of type 'object' is not assignable to parameter of type 'string'.
  When invoking "(s: object, opts: { fl...":
    TS2345: Argument of type '{ filename: string; }' is not assignable to parameter of type '{ fileName: string; }'.
      Object literal may only specify known properties, but 'filename' does not exist in type '{ fileName: string; }'. Did you mean to write 'fileName'?

Playground Link: Link

Related Issues: #26633, others certainly exist

See also https://github.com/garybernhardt/preact-typescript-component-wont-build

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Sep 20, 2018
@jack-williams
Copy link
Collaborator

jack-williams commented Sep 24, 2018

+1 on the suggestion.

Also, is there any overlap with @DanielRosenwasser's work on union error messages and overlappy-types? (#27087) Could similar ideas be used to try and report the overload the user probably meant.

In the example, there is an overlap between the first argument for the first overload, and no overlap for the second overload: so the user probably mean the first one.

For small numbers of overloads I think showing all the errors is best as it's quite informative to see TypeScript's reasoning for pruning overloads. My suggestion is really aimed at the larger cases where this wouldn't be tractable.

@RyanCavanaugh RyanCavanaugh added Committed The team has roadmapped this issue and removed In Discussion Not yet reached consensus labels Oct 9, 2018
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 3.3 milestone Oct 9, 2018
@RyanCavanaugh
Copy link
Member Author

Basic notes:

  • We should first filter by "close" arity
  • Then also filter by some rough estimate of type closeness of all arguments
  • Also include a related span for the overload we selected for the purposes of error reporting

Currently not in scope: Reporting for every plausible overload

@marvinhagemeister
Copy link

We are running into this issue with preactjs and fixed it by swapping the overloads around. It seems more like a workaround, but it does fix the issue for us for now. Choosing the declaration with the closest arity seems like the best bet to me. In our case the problematic function has this definition (simplified):

interface ComponentFactory<P> {
   props: P;
}

interface Attributes {}

function h<P>(
  node: ComponentFactory<P>,
  params: Attributes & P | null,
  ...children: any[]
): any;
function h(
  node: string,
  params: JSX.HTMLAttributes & JSX.SVGAttributes & Attributes | null,
  ...children: any[]
): any;

@bterlson
Copy link
Member

Came across this issue with the following code:

type Options = {
  x: number
}
declare function foo(a: string, b: Options): void;
declare function foo(a: number, b: Options): void;

foo('string', { y: 1 });

The error is that the options provided are incorrect, not that string isn't assignable to number. It seems like any functions which take options and have overloads will have poor error reporting when users provide incorrect options.

@garybernhardt
Copy link

Thanks for fixing this, @sandersn!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Committed The team has roadmapped this issue Suggestion An idea for TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants