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