Skip to content

Commit 598e9b2

Browse files
authored
Allow trailing params of 'undefined', 'unknown', and 'any' to be optional in non-strictNullChecks JS (#40057)
1 parent 76639f1 commit 598e9b2

8 files changed

+662
-1
lines changed

src/compiler/checker.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -25745,6 +25745,10 @@ namespace ts {
2574525745
return !!(t.flags & TypeFlags.Void);
2574625746
}
2574725747

25748+
function acceptsVoidUndefinedUnknownOrAny(t: Type): boolean {
25749+
return !!(t.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Unknown | TypeFlags.Any));
25750+
}
25751+
2574825752
function hasCorrectArity(node: CallLikeExpression, args: readonly Expression[], signature: Signature, signatureHelpTrailingComma = false) {
2574925753
let argCount: number;
2575025754
let callIsIncomplete = false; // In incomplete call we want to be lenient when we have too few arguments
@@ -25810,7 +25814,7 @@ namespace ts {
2581025814
}
2581125815
for (let i = argCount; i < effectiveMinimumArguments; i++) {
2581225816
const type = getTypeAtPosition(signature, i);
25813-
if (filterType(type, acceptsVoid).flags & TypeFlags.Never) {
25817+
if (filterType(type, isInJSFile(node) && !strictNullChecks ? acceptsVoidUndefinedUnknownOrAny : acceptsVoid).flags & TypeFlags.Never) {
2581425818
return false;
2581525819
}
2581625820
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
tests/cases/conformance/expressions/functionCalls/tsfile.ts(6,1): error TS2554: Expected 1 arguments, but got 0.
2+
tests/cases/conformance/expressions/functionCalls/tsfile.ts(7,1): error TS2554: Expected 1 arguments, but got 0.
3+
tests/cases/conformance/expressions/functionCalls/tsfile.ts(8,1): error TS2554: Expected 1 arguments, but got 0.
4+
tests/cases/conformance/expressions/functionCalls/tsfile.ts(10,4): error TS2554: Expected 1 arguments, but got 0.
5+
tests/cases/conformance/expressions/functionCalls/tsfile.ts(11,4): error TS2554: Expected 1 arguments, but got 0.
6+
tests/cases/conformance/expressions/functionCalls/tsfile.ts(12,4): error TS2554: Expected 1 arguments, but got 0.
7+
8+
9+
==== tests/cases/conformance/expressions/functionCalls/defs.d.ts (0 errors) ====
10+
declare function f1(p: void): void;
11+
declare function f2(p: undefined): void;
12+
declare function f3(p: unknown): void;
13+
declare function f4(p: any): void;
14+
15+
interface I<T> { m(p: T): void; }
16+
declare const o1: I<void>;
17+
declare const o2: I<undefined>;
18+
declare const o3: I<unknown>;
19+
declare const o4: I<any>;
20+
21+
==== tests/cases/conformance/expressions/functionCalls/jsfile.js (0 errors) ====
22+
// current behavior: treat trailing `void` as optional
23+
f1();
24+
o1.m();
25+
26+
// new behavior: treat 'undefined', 'unknown', and 'any' as optional in non-strict mode
27+
f2();
28+
f3();
29+
f4();
30+
31+
o2.m();
32+
o3.m();
33+
o4.m();
34+
35+
==== tests/cases/conformance/expressions/functionCalls/tsfile.ts (6 errors) ====
36+
// current behavior: treat trailing `void` as optional
37+
f1();
38+
o1.m();
39+
40+
// no change in behavior
41+
f2();
42+
~~~~
43+
!!! error TS2554: Expected 1 arguments, but got 0.
44+
!!! related TS6210 tests/cases/conformance/expressions/functionCalls/defs.d.ts:2:21: An argument for 'p' was not provided.
45+
f3();
46+
~~~~
47+
!!! error TS2554: Expected 1 arguments, but got 0.
48+
!!! related TS6210 tests/cases/conformance/expressions/functionCalls/defs.d.ts:3:21: An argument for 'p' was not provided.
49+
f4();
50+
~~~~
51+
!!! error TS2554: Expected 1 arguments, but got 0.
52+
!!! related TS6210 tests/cases/conformance/expressions/functionCalls/defs.d.ts:4:21: An argument for 'p' was not provided.
53+
54+
o2.m();
55+
~~~
56+
!!! error TS2554: Expected 1 arguments, but got 0.
57+
!!! related TS6210 tests/cases/conformance/expressions/functionCalls/defs.d.ts:6:20: An argument for 'p' was not provided.
58+
o3.m();
59+
~~~
60+
!!! error TS2554: Expected 1 arguments, but got 0.
61+
!!! related TS6210 tests/cases/conformance/expressions/functionCalls/defs.d.ts:6:20: An argument for 'p' was not provided.
62+
o4.m();
63+
~~~
64+
!!! error TS2554: Expected 1 arguments, but got 0.
65+
!!! related TS6210 tests/cases/conformance/expressions/functionCalls/defs.d.ts:6:20: An argument for 'p' was not provided.
66+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
=== tests/cases/conformance/expressions/functionCalls/defs.d.ts ===
2+
declare function f1(p: void): void;
3+
>f1 : Symbol(f1, Decl(defs.d.ts, 0, 0))
4+
>p : Symbol(p, Decl(defs.d.ts, 0, 20))
5+
6+
declare function f2(p: undefined): void;
7+
>f2 : Symbol(f2, Decl(defs.d.ts, 0, 35))
8+
>p : Symbol(p, Decl(defs.d.ts, 1, 20))
9+
10+
declare function f3(p: unknown): void;
11+
>f3 : Symbol(f3, Decl(defs.d.ts, 1, 40))
12+
>p : Symbol(p, Decl(defs.d.ts, 2, 20))
13+
14+
declare function f4(p: any): void;
15+
>f4 : Symbol(f4, Decl(defs.d.ts, 2, 38))
16+
>p : Symbol(p, Decl(defs.d.ts, 3, 20))
17+
18+
interface I<T> { m(p: T): void; }
19+
>I : Symbol(I, Decl(defs.d.ts, 3, 34))
20+
>T : Symbol(T, Decl(defs.d.ts, 5, 12))
21+
>m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
22+
>p : Symbol(p, Decl(defs.d.ts, 5, 19))
23+
>T : Symbol(T, Decl(defs.d.ts, 5, 12))
24+
25+
declare const o1: I<void>;
26+
>o1 : Symbol(o1, Decl(defs.d.ts, 6, 13))
27+
>I : Symbol(I, Decl(defs.d.ts, 3, 34))
28+
29+
declare const o2: I<undefined>;
30+
>o2 : Symbol(o2, Decl(defs.d.ts, 7, 13))
31+
>I : Symbol(I, Decl(defs.d.ts, 3, 34))
32+
33+
declare const o3: I<unknown>;
34+
>o3 : Symbol(o3, Decl(defs.d.ts, 8, 13))
35+
>I : Symbol(I, Decl(defs.d.ts, 3, 34))
36+
37+
declare const o4: I<any>;
38+
>o4 : Symbol(o4, Decl(defs.d.ts, 9, 13))
39+
>I : Symbol(I, Decl(defs.d.ts, 3, 34))
40+
41+
=== tests/cases/conformance/expressions/functionCalls/jsfile.js ===
42+
// current behavior: treat trailing `void` as optional
43+
f1();
44+
>f1 : Symbol(f1, Decl(defs.d.ts, 0, 0))
45+
46+
o1.m();
47+
>o1.m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
48+
>o1 : Symbol(o1, Decl(defs.d.ts, 6, 13))
49+
>m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
50+
51+
// new behavior: treat 'undefined', 'unknown', and 'any' as optional in non-strict mode
52+
f2();
53+
>f2 : Symbol(f2, Decl(defs.d.ts, 0, 35))
54+
55+
f3();
56+
>f3 : Symbol(f3, Decl(defs.d.ts, 1, 40))
57+
58+
f4();
59+
>f4 : Symbol(f4, Decl(defs.d.ts, 2, 38))
60+
61+
o2.m();
62+
>o2.m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
63+
>o2 : Symbol(o2, Decl(defs.d.ts, 7, 13))
64+
>m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
65+
66+
o3.m();
67+
>o3.m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
68+
>o3 : Symbol(o3, Decl(defs.d.ts, 8, 13))
69+
>m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
70+
71+
o4.m();
72+
>o4.m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
73+
>o4 : Symbol(o4, Decl(defs.d.ts, 9, 13))
74+
>m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
75+
76+
=== tests/cases/conformance/expressions/functionCalls/tsfile.ts ===
77+
// current behavior: treat trailing `void` as optional
78+
f1();
79+
>f1 : Symbol(f1, Decl(defs.d.ts, 0, 0))
80+
81+
o1.m();
82+
>o1.m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
83+
>o1 : Symbol(o1, Decl(defs.d.ts, 6, 13))
84+
>m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
85+
86+
// no change in behavior
87+
f2();
88+
>f2 : Symbol(f2, Decl(defs.d.ts, 0, 35))
89+
90+
f3();
91+
>f3 : Symbol(f3, Decl(defs.d.ts, 1, 40))
92+
93+
f4();
94+
>f4 : Symbol(f4, Decl(defs.d.ts, 2, 38))
95+
96+
o2.m();
97+
>o2.m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
98+
>o2 : Symbol(o2, Decl(defs.d.ts, 7, 13))
99+
>m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
100+
101+
o3.m();
102+
>o3.m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
103+
>o3 : Symbol(o3, Decl(defs.d.ts, 8, 13))
104+
>m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
105+
106+
o4.m();
107+
>o4.m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
108+
>o4 : Symbol(o4, Decl(defs.d.ts, 9, 13))
109+
>m : Symbol(I.m, Decl(defs.d.ts, 5, 16))
110+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
=== tests/cases/conformance/expressions/functionCalls/defs.d.ts ===
2+
declare function f1(p: void): void;
3+
>f1 : (p: void) => void
4+
>p : void
5+
6+
declare function f2(p: undefined): void;
7+
>f2 : (p: undefined) => void
8+
>p : undefined
9+
10+
declare function f3(p: unknown): void;
11+
>f3 : (p: unknown) => void
12+
>p : unknown
13+
14+
declare function f4(p: any): void;
15+
>f4 : (p: any) => void
16+
>p : any
17+
18+
interface I<T> { m(p: T): void; }
19+
>m : (p: T) => void
20+
>p : T
21+
22+
declare const o1: I<void>;
23+
>o1 : I<void>
24+
25+
declare const o2: I<undefined>;
26+
>o2 : I<undefined>
27+
28+
declare const o3: I<unknown>;
29+
>o3 : I<unknown>
30+
31+
declare const o4: I<any>;
32+
>o4 : I<any>
33+
34+
=== tests/cases/conformance/expressions/functionCalls/jsfile.js ===
35+
// current behavior: treat trailing `void` as optional
36+
f1();
37+
>f1() : void
38+
>f1 : (p: void) => void
39+
40+
o1.m();
41+
>o1.m() : void
42+
>o1.m : (p: void) => void
43+
>o1 : I<void>
44+
>m : (p: void) => void
45+
46+
// new behavior: treat 'undefined', 'unknown', and 'any' as optional in non-strict mode
47+
f2();
48+
>f2() : void
49+
>f2 : (p: undefined) => void
50+
51+
f3();
52+
>f3() : void
53+
>f3 : (p: unknown) => void
54+
55+
f4();
56+
>f4() : void
57+
>f4 : (p: any) => void
58+
59+
o2.m();
60+
>o2.m() : void
61+
>o2.m : (p: undefined) => void
62+
>o2 : I<undefined>
63+
>m : (p: undefined) => void
64+
65+
o3.m();
66+
>o3.m() : void
67+
>o3.m : (p: unknown) => void
68+
>o3 : I<unknown>
69+
>m : (p: unknown) => void
70+
71+
o4.m();
72+
>o4.m() : void
73+
>o4.m : (p: any) => void
74+
>o4 : I<any>
75+
>m : (p: any) => void
76+
77+
=== tests/cases/conformance/expressions/functionCalls/tsfile.ts ===
78+
// current behavior: treat trailing `void` as optional
79+
f1();
80+
>f1() : void
81+
>f1 : (p: void) => void
82+
83+
o1.m();
84+
>o1.m() : void
85+
>o1.m : (p: void) => void
86+
>o1 : I<void>
87+
>m : (p: void) => void
88+
89+
// no change in behavior
90+
f2();
91+
>f2() : void
92+
>f2 : (p: undefined) => void
93+
94+
f3();
95+
>f3() : void
96+
>f3 : (p: unknown) => void
97+
98+
f4();
99+
>f4() : void
100+
>f4 : (p: any) => void
101+
102+
o2.m();
103+
>o2.m() : void
104+
>o2.m : (p: undefined) => void
105+
>o2 : I<undefined>
106+
>m : (p: undefined) => void
107+
108+
o3.m();
109+
>o3.m() : void
110+
>o3.m : (p: unknown) => void
111+
>o3 : I<unknown>
112+
>m : (p: unknown) => void
113+
114+
o4.m();
115+
>o4.m() : void
116+
>o4.m : (p: any) => void
117+
>o4 : I<any>
118+
>m : (p: any) => void
119+

0 commit comments

Comments
 (0)