Skip to content

Commit 96937fd

Browse files
authored
Allow union signatures to merge when they have differing argument counts (#28604)
* Allow union signatures to merge when they have differing argument counts * Accept updated baselines * Adjust comments io changed tests
1 parent ddded2d commit 96937fd

21 files changed

+362
-191
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13105,13 +13105,8 @@ namespace ts {
1310513105
return true;
1310613106
}
1310713107
// A source signature partially matches a target signature if the target signature has no fewer required
13108-
// parameters and no more overall parameters than the source signature (where a signature with a rest
13109-
// parameter is always considered to have more overall parameters than one without).
13110-
const sourceRestCount = sourceHasRestParameter ? 1 : 0;
13111-
const targetRestCount = targetHasRestParameter ? 1 : 0;
13112-
if (partialMatch && sourceMinArgumentCount <= targetMinArgumentCount && (
13113-
sourceRestCount > targetRestCount ||
13114-
sourceRestCount === targetRestCount && sourceParameterCount >= targetParameterCount)) {
13108+
// parameters
13109+
if (partialMatch && sourceMinArgumentCount <= targetMinArgumentCount) {
1311513110
return true;
1311613111
}
1311713112
return false;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//// [reactSFCAndFunctionResolvable.tsx]
2+
/// <reference path="/.lib/react16.d.ts" />
3+
4+
import * as React from 'react';
5+
6+
declare const Radio: (props: {}) => React.ReactElement<{}>;
7+
declare const OtherRadio: () => React.ReactElement<{}>;
8+
declare const Checkbox: React.SFC;
9+
10+
declare const condition1: boolean;
11+
declare const condition2: boolean;
12+
declare const condition3: boolean;
13+
14+
const RandomComponent: React.SFC = () => {
15+
const Component =
16+
condition1
17+
? Radio
18+
: Checkbox;
19+
20+
const OtherComponent =
21+
condition2
22+
? OtherRadio
23+
: Checkbox;
24+
return condition1 ? <Component /> : <OtherComponent />;
25+
};
26+
27+
28+
//// [reactSFCAndFunctionResolvable.js]
29+
"use strict";
30+
/// <reference path="react16.d.ts" />
31+
exports.__esModule = true;
32+
var React = require("react");
33+
var RandomComponent = function () {
34+
var Component = condition1
35+
? Radio
36+
: Checkbox;
37+
var OtherComponent = condition2
38+
? OtherRadio
39+
: Checkbox;
40+
return condition1 ? React.createElement(Component, null) : React.createElement(OtherComponent, null);
41+
};
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
=== tests/cases/compiler/reactSFCAndFunctionResolvable.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
4+
import * as React from 'react';
5+
>React : Symbol(React, Decl(reactSFCAndFunctionResolvable.tsx, 2, 6))
6+
7+
declare const Radio: (props: {}) => React.ReactElement<{}>;
8+
>Radio : Symbol(Radio, Decl(reactSFCAndFunctionResolvable.tsx, 4, 13))
9+
>props : Symbol(props, Decl(reactSFCAndFunctionResolvable.tsx, 4, 22))
10+
>React : Symbol(React, Decl(reactSFCAndFunctionResolvable.tsx, 2, 6))
11+
>ReactElement : Symbol(React.ReactElement, Decl(react16.d.ts, 135, 9))
12+
13+
declare const OtherRadio: () => React.ReactElement<{}>;
14+
>OtherRadio : Symbol(OtherRadio, Decl(reactSFCAndFunctionResolvable.tsx, 5, 13))
15+
>React : Symbol(React, Decl(reactSFCAndFunctionResolvable.tsx, 2, 6))
16+
>ReactElement : Symbol(React.ReactElement, Decl(react16.d.ts, 135, 9))
17+
18+
declare const Checkbox: React.SFC;
19+
>Checkbox : Symbol(Checkbox, Decl(reactSFCAndFunctionResolvable.tsx, 6, 13))
20+
>React : Symbol(React, Decl(reactSFCAndFunctionResolvable.tsx, 2, 6))
21+
>SFC : Symbol(React.SFC, Decl(react16.d.ts, 400, 9))
22+
23+
declare const condition1: boolean;
24+
>condition1 : Symbol(condition1, Decl(reactSFCAndFunctionResolvable.tsx, 8, 13))
25+
26+
declare const condition2: boolean;
27+
>condition2 : Symbol(condition2, Decl(reactSFCAndFunctionResolvable.tsx, 9, 13))
28+
29+
declare const condition3: boolean;
30+
>condition3 : Symbol(condition3, Decl(reactSFCAndFunctionResolvable.tsx, 10, 13))
31+
32+
const RandomComponent: React.SFC = () => {
33+
>RandomComponent : Symbol(RandomComponent, Decl(reactSFCAndFunctionResolvable.tsx, 12, 5))
34+
>React : Symbol(React, Decl(reactSFCAndFunctionResolvable.tsx, 2, 6))
35+
>SFC : Symbol(React.SFC, Decl(react16.d.ts, 400, 9))
36+
37+
const Component =
38+
>Component : Symbol(Component, Decl(reactSFCAndFunctionResolvable.tsx, 13, 7))
39+
40+
condition1
41+
>condition1 : Symbol(condition1, Decl(reactSFCAndFunctionResolvable.tsx, 8, 13))
42+
43+
? Radio
44+
>Radio : Symbol(Radio, Decl(reactSFCAndFunctionResolvable.tsx, 4, 13))
45+
46+
: Checkbox;
47+
>Checkbox : Symbol(Checkbox, Decl(reactSFCAndFunctionResolvable.tsx, 6, 13))
48+
49+
const OtherComponent =
50+
>OtherComponent : Symbol(OtherComponent, Decl(reactSFCAndFunctionResolvable.tsx, 18, 7))
51+
52+
condition2
53+
>condition2 : Symbol(condition2, Decl(reactSFCAndFunctionResolvable.tsx, 9, 13))
54+
55+
? OtherRadio
56+
>OtherRadio : Symbol(OtherRadio, Decl(reactSFCAndFunctionResolvable.tsx, 5, 13))
57+
58+
: Checkbox;
59+
>Checkbox : Symbol(Checkbox, Decl(reactSFCAndFunctionResolvable.tsx, 6, 13))
60+
61+
return condition1 ? <Component /> : <OtherComponent />;
62+
>condition1 : Symbol(condition1, Decl(reactSFCAndFunctionResolvable.tsx, 8, 13))
63+
>Component : Symbol(Component, Decl(reactSFCAndFunctionResolvable.tsx, 13, 7))
64+
>OtherComponent : Symbol(OtherComponent, Decl(reactSFCAndFunctionResolvable.tsx, 18, 7))
65+
66+
};
67+
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
=== tests/cases/compiler/reactSFCAndFunctionResolvable.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
4+
import * as React from 'react';
5+
>React : typeof React
6+
7+
declare const Radio: (props: {}) => React.ReactElement<{}>;
8+
>Radio : (props: {}) => React.ReactElement<{}>
9+
>props : {}
10+
>React : any
11+
12+
declare const OtherRadio: () => React.ReactElement<{}>;
13+
>OtherRadio : () => React.ReactElement<{}>
14+
>React : any
15+
16+
declare const Checkbox: React.SFC;
17+
>Checkbox : React.StatelessComponent<{}>
18+
>React : any
19+
20+
declare const condition1: boolean;
21+
>condition1 : boolean
22+
23+
declare const condition2: boolean;
24+
>condition2 : boolean
25+
26+
declare const condition3: boolean;
27+
>condition3 : boolean
28+
29+
const RandomComponent: React.SFC = () => {
30+
>RandomComponent : React.StatelessComponent<{}>
31+
>React : any
32+
>() => { const Component = condition1 ? Radio : Checkbox; const OtherComponent = condition2 ? OtherRadio : Checkbox; return condition1 ? <Component /> : <OtherComponent />;} : () => JSX.Element
33+
34+
const Component =
35+
>Component : React.StatelessComponent<{}> | ((props: {}) => React.ReactElement<{}>)
36+
37+
condition1
38+
>condition1 ? Radio : Checkbox : React.StatelessComponent<{}> | ((props: {}) => React.ReactElement<{}>)
39+
>condition1 : boolean
40+
41+
? Radio
42+
>Radio : (props: {}) => React.ReactElement<{}>
43+
44+
: Checkbox;
45+
>Checkbox : React.StatelessComponent<{}>
46+
47+
const OtherComponent =
48+
>OtherComponent : React.StatelessComponent<{}> | (() => React.ReactElement<{}>)
49+
50+
condition2
51+
>condition2 ? OtherRadio : Checkbox : React.StatelessComponent<{}> | (() => React.ReactElement<{}>)
52+
>condition2 : boolean
53+
54+
? OtherRadio
55+
>OtherRadio : () => React.ReactElement<{}>
56+
57+
: Checkbox;
58+
>Checkbox : React.StatelessComponent<{}>
59+
60+
return condition1 ? <Component /> : <OtherComponent />;
61+
>condition1 ? <Component /> : <OtherComponent /> : JSX.Element
62+
>condition1 : boolean
63+
><Component /> : JSX.Element
64+
>Component : React.StatelessComponent<{}> | ((props: {}) => React.ReactElement<{}>)
65+
><OtherComponent /> : JSX.Element
66+
>OtherComponent : React.StatelessComponent<{}> | (() => React.ReactElement<{}>)
67+
68+
};
69+

tests/baselines/reference/unionTypeCallSignatures.errors.txt

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,27 @@ tests/cases/conformance/types/union/unionTypeCallSignatures.ts(20,1): error TS23
77
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(21,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '((a: number) => number) | ((a: string) => Date)' has no compatible call signatures.
88
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(24,1): error TS2554: Expected 1 arguments, but got 0.
99
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(26,36): error TS2345: Argument of type '"hello"' is not assignable to parameter of type 'number'.
10-
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(29,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '((a: string) => string) | ((a: string, b: number) => number)' has no compatible call signatures.
11-
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(30,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '((a: string) => string) | ((a: string, b: number) => number)' has no compatible call signatures.
12-
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(31,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '((a: string) => string) | ((a: string, b: number) => number)' has no compatible call signatures.
10+
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(29,1): error TS2554: Expected 2 arguments, but got 0.
11+
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(30,1): error TS2554: Expected 2 arguments, but got 1.
1312
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(36,49): error TS2345: Argument of type '"hello"' is not assignable to parameter of type 'number'.
1413
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(37,12): error TS2554: Expected 1-2 arguments, but got 0.
1514
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(40,12): error TS2554: Expected 2 arguments, but got 1.
1615
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(42,49): error TS2345: Argument of type '"hello"' is not assignable to parameter of type 'number'.
1716
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(43,12): error TS2554: Expected 2 arguments, but got 0.
18-
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(47,12): error TS2554: Expected 1 arguments, but got 2.
19-
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(48,12): error TS2554: Expected 1 arguments, but got 2.
20-
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(49,12): error TS2554: Expected 1 arguments, but got 0.
17+
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(48,49): error TS2345: Argument of type '"hello"' is not assignable to parameter of type 'number'.
18+
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(49,12): error TS2554: Expected 1-2 arguments, but got 0.
2119
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(55,45): error TS2345: Argument of type '"hello"' is not assignable to parameter of type 'number'.
2220
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(56,12): error TS2555: Expected at least 1 arguments, but got 0.
2321
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(59,12): error TS2554: Expected 2 arguments, but got 1.
2422
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(61,12): error TS2554: Expected 2 arguments, but got 3.
2523
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(62,45): error TS2345: Argument of type '"hello"' is not assignable to parameter of type 'number'.
2624
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(63,12): error TS2554: Expected 2 arguments, but got 0.
27-
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(67,12): error TS2554: Expected 1 arguments, but got 2.
28-
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(68,12): error TS2554: Expected 1 arguments, but got 3.
29-
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(69,12): error TS2554: Expected 1 arguments, but got 2.
30-
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(70,12): error TS2554: Expected 1 arguments, but got 0.
25+
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(69,45): error TS2345: Argument of type '"hello"' is not assignable to parameter of type 'number'.
26+
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(70,12): error TS2555: Expected at least 1 arguments, but got 0.
3127
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(73,12): error TS2554: Expected 2 arguments, but got 1.
3228

3329

34-
==== tests/cases/conformance/types/union/unionTypeCallSignatures.ts (31 errors) ====
30+
==== tests/cases/conformance/types/union/unionTypeCallSignatures.ts (27 errors) ====
3531
var numOrDate: number | Date;
3632
var strOrBoolean: string | boolean;
3733
var strOrNum: string | number;
@@ -80,15 +76,15 @@ tests/cases/conformance/types/union/unionTypeCallSignatures.ts(73,12): error TS2
8076
!!! error TS2345: Argument of type '"hello"' is not assignable to parameter of type 'number'.
8177

8278
var unionWithDifferentParameterCount: { (a: string): string; } | { (a: string, b: number): number; } ;
83-
unionWithDifferentParameterCount();// no call signature
79+
unionWithDifferentParameterCount();// needs more args
8480
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
85-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '((a: string) => string) | ((a: string, b: number) => number)' has no compatible call signatures.
86-
unionWithDifferentParameterCount("hello");// no call signature
81+
!!! error TS2554: Expected 2 arguments, but got 0.
82+
!!! related TS6210 tests/cases/conformance/types/union/unionTypeCallSignatures.ts:28:69: An argument for 'a' was not provided.
83+
unionWithDifferentParameterCount("hello");// needs more args
8784
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
88-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '((a: string) => string) | ((a: string, b: number) => number)' has no compatible call signatures.
89-
unionWithDifferentParameterCount("hello", 10);// no call signature
90-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
91-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '((a: string) => string) | ((a: string, b: number) => number)' has no compatible call signatures.
85+
!!! error TS2554: Expected 2 arguments, but got 1.
86+
!!! related TS6210 tests/cases/conformance/types/union/unionTypeCallSignatures.ts:28:80: An argument for 'b' was not provided.
87+
unionWithDifferentParameterCount("hello", 10);// OK
9288

9389
var unionWithOptionalParameter1: { (a: string, b?: number): string; } | { (a: string, b?: number): number; };
9490
strOrNum = unionWithOptionalParameter1('hello');
@@ -117,16 +113,14 @@ tests/cases/conformance/types/union/unionTypeCallSignatures.ts(73,12): error TS2
117113

118114
var unionWithOptionalParameter3: { (a: string, b?: number): string; } | { (a: string): number; };
119115
strOrNum = unionWithOptionalParameter3('hello');
120-
strOrNum = unionWithOptionalParameter3('hello', 10); // error no call signature
121-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
122-
!!! error TS2554: Expected 1 arguments, but got 2.
123-
strOrNum = unionWithOptionalParameter3('hello', "hello"); // error no call signature
124-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
125-
!!! error TS2554: Expected 1 arguments, but got 2.
126-
strOrNum = unionWithOptionalParameter3(); // error no call signature
116+
strOrNum = unionWithOptionalParameter3('hello', 10); // ok
117+
strOrNum = unionWithOptionalParameter3('hello', "hello"); // wrong argument type
118+
~~~~~~~
119+
!!! error TS2345: Argument of type '"hello"' is not assignable to parameter of type 'number'.
120+
strOrNum = unionWithOptionalParameter3(); // needs more args
127121
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
128-
!!! error TS2554: Expected 1 arguments, but got 0.
129-
!!! related TS6210 tests/cases/conformance/types/union/unionTypeCallSignatures.ts:45:76: An argument for 'a' was not provided.
122+
!!! error TS2554: Expected 1-2 arguments, but got 0.
123+
!!! related TS6210 tests/cases/conformance/types/union/unionTypeCallSignatures.ts:45:37: An argument for 'a' was not provided.
130124

131125
var unionWithRestParameter1: { (a: string, ...b: number[]): string; } | { (a: string, ...b: number[]): number };
132126
strOrNum = unionWithRestParameter1('hello');
@@ -160,18 +154,14 @@ tests/cases/conformance/types/union/unionTypeCallSignatures.ts(73,12): error TS2
160154
var unionWithRestParameter3: { (a: string, ...b: number[]): string; } | { (a: string): number };
161155
strOrNum = unionWithRestParameter3('hello');
162156
strOrNum = unionWithRestParameter3('hello', 10); // error no call signature
163-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
164-
!!! error TS2554: Expected 1 arguments, but got 2.
165157
strOrNum = unionWithRestParameter3('hello', 10, 11); // error no call signature
166-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
167-
!!! error TS2554: Expected 1 arguments, but got 3.
168-
strOrNum = unionWithRestParameter3('hello', "hello"); // error no call signature
169-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
170-
!!! error TS2554: Expected 1 arguments, but got 2.
158+
strOrNum = unionWithRestParameter3('hello', "hello"); // wrong argument type
159+
~~~~~~~
160+
!!! error TS2345: Argument of type '"hello"' is not assignable to parameter of type 'number'.
171161
strOrNum = unionWithRestParameter3(); // error no call signature
172162
~~~~~~~~~~~~~~~~~~~~~~~~~
173-
!!! error TS2554: Expected 1 arguments, but got 0.
174-
!!! related TS6210 tests/cases/conformance/types/union/unionTypeCallSignatures.ts:65:76: An argument for 'a' was not provided.
163+
!!! error TS2555: Expected at least 1 arguments, but got 0.
164+
!!! related TS6210 tests/cases/conformance/types/union/unionTypeCallSignatures.ts:65:33: An argument for 'a' was not provided.
175165

176166
var unionWithRestParameter4: { (...a: string[]): string; } | { (a: string, b: string): number; };
177167
strOrNum = unionWithRestParameter4("hello"); // error supplied parameters do not match any call signature

0 commit comments

Comments
 (0)