10000 Union types do not understand function overloads and cause an error · Issue #49076 · microsoft/TypeScript · GitHub
[go: up one dir, main page]

Skip to content
Union types do not understand function overloads and cause an error #49076
Closed as not planned
@maludwig

Description

@maludwig

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0