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

Union types do not understand function overloads and cause an error #49076

Closed
maludwig opened this issue May 12, 2022 · 2 comments
Closed

Union types do not understand function overloads and cause an error #49076

maludwig opened this issue May 12, 2022 · 2 comments
Labels
Duplicate An existing issue was already created

Comments

@maludwig
Copy link

Bug Report

🔎 Search Terms

  • Overloading
  • TS2769: No overload matches this call.

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about overloads not matching this

⏯ Playground Link

Playground link with relevant code

💻 Code

export function stringChecker(a: string, b: string): boolean
export function stringChecker(a: string, b: RegExp): boolean

export function stringChecker(a: string, b: string | RegExp): boolean {
  if (typeof b === 'string') {
    return a === b
  } else {
    // If b instanceof RegExp
    return b.test(a)
  }
}

const tests: { [key: string]: string | RegExp } = {
  is_it_an_a: 'a',
  is_it_a_b: 'b',
  is_it_a_letter: /[a-z]/,
}

for (const test_name in tests) {
  const test_value = tests[test_name]
  if (stringChecker('b', test_value)) {
    console.log(`'b' passes the ${test_name} test!`)
  } else {
    console.log(`'b' fails the ${test_name} test!`)
  }
}

🙁 Actual behavior

For clarity, I'm not sure if this should be classified as a bug or a feature, but it feels like a bug to me, so I made a bug ticket. I'm sorry if that's wrong.

I get an error here:

TS2769: No overload matches this call.   
Overload 1 of 2, '(a: string, b: string): boolean', gave the following error.     
Argument of type 'string | RegExp' is not assignable to parameter of type 'string'.       Type 'RegExp' is not assignable to type 'string'.   
Overload 2 of 2, '(a: string, b: RegExp): boolean', gave the following error.    
Argument of type 'string | RegExp' is not assignable to parameter of type 'RegExp'.       Type 'string' is not assignable to type 'RegExp'.

The function overloads allow for a string or a RegExp, but passing in a variable that is of type string | RegExp does not cause TypeScript to understand that this function has an overload for both cases. TypeScript should ask, "if it is a string, would this all work?" and then ask "if it is a RegExp, would this all work?"

This is obviously a trivial example, since I could omit the overloads and it would all work just fine, but it is frustrating for a library like supertest which a non-trival case of wanting to list all of the available overloads:

From: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/supertest/index.d.ts


    interface Test extends superagent.SuperAgentRequest {
        app?: any;
        url: string;
        serverAddress(app: any, path: string): string;
        expect(status: number, callback?: CallbackHandler): this;
        expect(status: number, body: any, callback?: CallbackHandler): this;
        expect(checker: (res: Response) => any, callback?: CallbackHandler): this;
        expect(body: string, callback?: CallbackHandler): this;
        expect(body: RegExp, callback?: CallbackHandler): this;
        expect(body: Object, callback?: CallbackHandler): this;
        expect(field: string, val: string, callback?: CallbackHandler): this;
        expect(field: string, val: RegExp, callback?: CallbackHandler): this;
        end(callback?: CallbackHandler): this;
    }

I could avoid this bug in my code with this pattern, but it looks extremely silly to have the same code in both branches of a conditional:


for (const [test_name, test_value] of Object.entries(tests)) {
  if (test_value instanceof RegExp) {
    if (stringChecker('b', test_value)) {
      console.log(`'b' passes the ${test_name} test!`)
    } else {
      console.log(`'b' fails the ${test_name} test!`)
    }
  } else {
    if (stringChecker('b', test_value)) {
      console.log(`'b' passes the ${test_name} test!`)
    } else {
      console.log(`'b' fails the ${test_name} test!`)
    }
  }
}

🙂 Expected behavior

The code should just compile without complaints. Whoever makes the supertest npm package shouldn't need to manually specify every permutation of overload, in addition to specifying a particular overload. TypeScript should just accept that the code is fine.

@jcalz
Copy link
Contributor

jcalz commented May 12, 2022

Duplicate of #14107

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label May 12, 2022
@maludwig
Copy link
Author

Should I close this one? It is defs a duplicate.

@RyanCavanaugh RyanCavanaugh closed this as not planned Won't fix, can't repro, duplicate, stale May 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants