From 54b5ad04e73ee7dae218a4eb40bc317622d987ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 21 Aug 2023 15:32:41 +0200 Subject: [PATCH] Prefer non-partial signature match in non-generic case --- src/compiler/checker.ts | 7 +++-- .../unionTypeCallSignatures6.errors.txt | 14 ++-------- .../unionTypeCallSignatures7.symbols | 26 +++++++++++++++++++ .../reference/unionTypeCallSignatures7.types | 20 ++++++++++++++ .../types/union/unionTypeCallSignatures7.ts | 12 +++++++++ 5 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 tests/baselines/reference/unionTypeCallSignatures7.symbols create mode 100644 tests/baselines/reference/unionTypeCallSignatures7.types create mode 100644 tests/cases/conformance/types/union/unionTypeCallSignatures7.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9c6b8237a7f74..0d9432c3bb51b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13019,9 +13019,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } let result: Signature[] | undefined; for (let i = 0; i < signatureLists.length; i++) { - // Allow matching non-generic signatures to have excess parameters and different return types. + // Allow matching non-generic signatures to have excess parameters (as a fallback if exact parameter match is not found) and different return types. // Prefer matching this types if possible. - const match = i === listIndex ? signature : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true); + const match = i === listIndex + ? signature + : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true) + || findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true); if (!match) { return undefined; } diff --git a/tests/baselines/reference/unionTypeCallSignatures6.errors.txt b/tests/baselines/reference/unionTypeCallSignatures6.errors.txt index d04dd49fdb30d..a3e4e593fc469 100644 --- a/tests/baselines/reference/unionTypeCallSignatures6.errors.txt +++ b/tests/baselines/reference/unionTypeCallSignatures6.errors.txt @@ -6,12 +6,7 @@ unionTypeCallSignatures6.ts(38,4): error TS2349: This expression is not callable unionTypeCallSignatures6.ts(39,1): error TS2684: The 'this' context of type 'A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; }' is not assignable to method's 'this' of type 'B'. Property 'b' is missing in type 'A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; }' but required in type 'B'. unionTypeCallSignatures6.ts(48,1): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. -unionTypeCallSignatures6.ts(55,1): error TS2769: No overload matches this call. - Overload 1 of 2, '(this: A & B & C): void', gave the following error. - The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B & C'. - Type 'void' is not assignable to type 'A'. - Overload 2 of 2, '(this: A & B): void', gave the following error. - The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. +unionTypeCallSignatures6.ts(55,1): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. ==== unionTypeCallSignatures6.ts (6 errors) ==== @@ -85,10 +80,5 @@ unionTypeCallSignatures6.ts(55,1): error TS2769: No overload matches this call. declare var f4: F6 | F7; f4(); // error ~~~~ -!!! error TS2769: No overload matches this call. -!!! error TS2769: Overload 1 of 2, '(this: A & B & C): void', gave the following error. -!!! error TS2769: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B & C'. -!!! error TS2769: Type 'void' is not assignable to type 'A'. -!!! error TS2769: Overload 2 of 2, '(this: A & B): void', gave the following error. -!!! error TS2769: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. +!!! error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. \ No newline at end of file diff --git a/tests/baselines/reference/unionTypeCallSignatures7.symbols b/tests/baselines/reference/unionTypeCallSignatures7.symbols new file mode 100644 index 0000000000000..4082ac252487b --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures7.symbols @@ -0,0 +1,26 @@ +//// [tests/cases/conformance/types/union/unionTypeCallSignatures7.ts] //// + +=== unionTypeCallSignatures7.ts === +// https://github.com/microsoft/TypeScript/issues/55203 + +interface Callable { +>Callable : Symbol(Callable, Decl(unionTypeCallSignatures7.ts, 0, 0)) +>Name : Symbol(Name, Decl(unionTypeCallSignatures7.ts, 2, 19)) + + (): `${Name} without id`; +>Name : Symbol(Name, Decl(unionTypeCallSignatures7.ts, 2, 19)) + + (id: number): `${Name} with id`; +>id : Symbol(id, Decl(unionTypeCallSignatures7.ts, 4, 3)) +>Name : Symbol(Name, Decl(unionTypeCallSignatures7.ts, 2, 19)) +} + +declare const f: Callable<"A"> | Callable<"B">; +>f : Symbol(f, Decl(unionTypeCallSignatures7.ts, 7, 13)) +>Callable : Symbol(Callable, Decl(unionTypeCallSignatures7.ts, 0, 0)) +>Callable : Symbol(Callable, Decl(unionTypeCallSignatures7.ts, 0, 0)) + +const result = f(123); +>result : Symbol(result, Decl(unionTypeCallSignatures7.ts, 8, 5)) +>f : Symbol(f, Decl(unionTypeCallSignatures7.ts, 7, 13)) + diff --git a/tests/baselines/reference/unionTypeCallSignatures7.types b/tests/baselines/reference/unionTypeCallSignatures7.types new file mode 100644 index 0000000000000..9d777eb4c0005 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures7.types @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/types/union/unionTypeCallSignatures7.ts] //// + +=== unionTypeCallSignatures7.ts === +// https://github.com/microsoft/TypeScript/issues/55203 + +interface Callable { + (): `${Name} without id`; + (id: number): `${Name} with id`; +>id : number +} + +declare const f: Callable<"A"> | Callable<"B">; +>f : Callable<"A"> | Callable<"B"> + +const result = f(123); +>result : "A with id" | "B with id" +>f(123) : "A with id" | "B with id" +>f : Callable<"A"> | Callable<"B"> +>123 : 123 + diff --git a/tests/cases/conformance/types/union/unionTypeCallSignatures7.ts b/tests/cases/conformance/types/union/unionTypeCallSignatures7.ts new file mode 100644 index 0000000000000..8c889ee459164 --- /dev/null +++ b/tests/cases/conformance/types/union/unionTypeCallSignatures7.ts @@ -0,0 +1,12 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/55203 + +interface Callable { + (): `${Name} without id`; + (id: number): `${Name} with id`; +} + +declare const f: Callable<"A"> | Callable<"B">; +const result = f(123);