Skip to content

Commit 9b4956f

Browse files
committed
Merge pull request microsoft#5459 from Microsoft/partialSignatureMatching
Fix union type partial signature matching
2 parents 12c6a74 + 31331ff commit 9b4956f

4 files changed

Lines changed: 132 additions & 8 deletions

File tree

src/compiler/checker.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5606,18 +5606,31 @@ namespace ts {
56065606
return compareTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp));
56075607
}
56085608

5609+
function isMatchingSignature(source: Signature, target: Signature, partialMatch: boolean) {
5610+
// A source signature matches a target signature if the two signatures have the same number of required,
5611+
// optional, and rest parameters.
5612+
if (source.parameters.length === target.parameters.length &&
5613+
source.minArgumentCount === target.minArgumentCount &&
5614+
source.hasRestParameter === target.hasRestParameter) {
5615+
return true;
5616+
}
5617+
// A source signature partially matches a target signature if the target signature has no fewer required
5618+
// parameters and no more overall parameters than the source signature (where a signature with a rest
5619+
// parameter is always considered to have more overall parameters than one without).
5620+
if (partialMatch && source.minArgumentCount <= target.minArgumentCount && (
5621+
source.hasRestParameter && !target.hasRestParameter ||
5622+
source.hasRestParameter === target.hasRestParameter && source.parameters.length >= target.parameters.length)) {
5623+
return true;
5624+
}
5625+
return false;
5626+
}
5627+
56095628
function compareSignatures(source: Signature, target: Signature, partialMatch: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
56105629
if (source === target) {
56115630
return Ternary.True;
56125631
}
5613-
if (source.parameters.length !== target.parameters.length ||
5614-
source.minArgumentCount !== target.minArgumentCount ||
5615-
source.hasRestParameter !== target.hasRestParameter) {
5616-
if (!partialMatch ||
5617-
source.parameters.length < target.parameters.length && !source.hasRestParameter ||
5618-
source.minArgumentCount > target.minArgumentCount) {
5619-
return Ternary.False;
5620-
}
5632+
if (!(isMatchingSignature(source, target, partialMatch))) {
5633+
return Ternary.False;
56215634
}
56225635
let result = Ternary.True;
56235636
if (source.typeParameters && target.typeParameters) {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
tests/cases/conformance/types/union/unionTypeCallSignatures4.ts(10,1): error TS2346: Supplied parameters do not match any signature of call target.
2+
tests/cases/conformance/types/union/unionTypeCallSignatures4.ts(20,1): error TS2346: Supplied parameters do not match any signature of call target.
3+
tests/cases/conformance/types/union/unionTypeCallSignatures4.ts(23,1): error TS2346: Supplied parameters do not match any signature of call target.
4+
tests/cases/conformance/types/union/unionTypeCallSignatures4.ts(25,1): error TS2346: Supplied parameters do not match any signature of call target.
5+
6+
7+
==== tests/cases/conformance/types/union/unionTypeCallSignatures4.ts (4 errors) ====
8+
type F1 = (a: string, b?: string) => void;
9+
type F2 = (a: string, b?: string, c?: string) => void;
10+
type F3 = (a: string, ...rest: string[]) => void;
11+
type F4 = (a: string, b?: string, ...rest: string[]) => void;
12+
type F5 = (a: string, b: string) => void;
13+
14+
var f12: F1 | F2;
15+
f12("a");
16+
f12("a", "b");
17+
f12("a", "b", "c"); // error
18+
~~~~~~~~~~~~~~~~~~
19+
!!! error TS2346: Supplied parameters do not match any signature of call target.
20+
21+
var f34: F3 | F4;
22+
f34("a");
23+
f34("a", "b");
24+
f34("a", "b", "c");
25+
26+
var f1234: F1 | F2 | F3 | F4;
27+
f1234("a");
28+
f1234("a", "b");
29+
f1234("a", "b", "c"); // error
30+
~~~~~~~~~~~~~~~~~~~~
31+
!!! error TS2346: Supplied parameters do not match any signature of call target.
32+
33+
var f12345: F1 | F2 | F3 | F4 | F5;
34+
f12345("a"); // error
35+
~~~~~~~~~~~
36+
!!! error TS2346: Supplied parameters do not match any signature of call target.
37+
f12345("a", "b");
38+
f12345("a", "b", "c"); // error
39+
~~~~~~~~~~~~~~~~~~~~~
40+
!!! error TS2346: Supplied parameters do not match any signature of call target.
41+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//// [unionTypeCallSignatures4.ts]
2+
type F1 = (a: string, b?: string) => void;
3+
type F2 = (a: string, b?: string, c?: string) => void;
4+
type F3 = (a: string, ...rest: string[]) => void;
5+
type F4 = (a: string, b?: string, ...rest: string[]) => void;
6+
type F5 = (a: string, b: string) => void;
7+
8+
var f12: F1 | F2;
9+
f12("a");
10+
f12("a", "b");
11+
f12("a", "b", "c"); // error
12+
13+
var f34: F3 | F4;
14+
f34("a");
15+
f34("a", "b");
16+
f34("a", "b", "c");
17+
18+
var f1234: F1 | F2 | F3 | F4;
19+
f1234("a");
20+
f1234("a", "b");
21+
f1234("a", "b", "c"); // error
22+
23+
var f12345: F1 | F2 | F3 | F4 | F5;
24+
f12345("a"); // error
25+
f12345("a", "b");
26+
f12345("a", "b", "c"); // error
27+
28+
29+
//// [unionTypeCallSignatures4.js]
30+
var f12;
31+
f12("a");
32+
f12("a", "b");
33+
f12("a", "b", "c"); // error
34+
var f34;
35+
f34("a");
36+
f34("a", "b");
37+
f34("a", "b", "c");
38+
var f1234;
39+
f1234("a");
40+
f1234("a", "b");
41+
f1234("a", "b", "c"); // error
42+
var f12345;
43+
f12345("a"); // error
44+
f12345("a", "b");
45+
f12345("a", "b", "c"); // error
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
type F1 = (a: string, b?: string) => void;
2+
type F2 = (a: string, b?: string, c?: string) => void;
3+
type F3 = (a: string, ...rest: string[]) => void;
4+
type F4 = (a: string, b?: string, ...rest: string[]) => void;
5+
type F5 = (a: string, b: string) => void;
6+
7+
var f12: F1 | F2;
8+
f12("a");
9+
f12("a", "b");
10+
f12("a", "b", "c"); // error
11+
12+
var f34: F3 | F4;
13+
f34("a");
14+
f34("a", "b");
15+
f34("a", "b", "c");
16+
17+
var f1234: F1 | F2 | F3 | F4;
18+
f1234("a");
19+
f1234("a", "b");
20+
f1234("a", "b", "c"); // error
21+
22+
var f12345: F1 | F2 | F3 | F4 | F5;
23+
f12345("a"); // error
24+
f12345("a", "b");
25+
f12345("a", "b", "c"); // error

0 commit comments

Comments
 (0)