Skip to content

Commit fdcc7cc

Browse files
authored
Merge pull request #11905 from Microsoft/skip-overloads-with-too-short-function-parameters
Skip overloads with too short function parameters
2 parents 4513ae3 + 1796826 commit fdcc7cc

6 files changed

+416
-10
lines changed

src/compiler/checker.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10328,16 +10328,32 @@ namespace ts {
1032810328

1032910329
// If the given type is an object or union type, if that type has a single signature, and if
1033010330
// that signature is non-generic, return the signature. Otherwise return undefined.
10331-
function getNonGenericSignature(type: Type): Signature {
10331+
function getNonGenericSignature(type: Type, node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature {
1033210332
const signatures = getSignaturesOfStructuredType(type, SignatureKind.Call);
1033310333
if (signatures.length === 1) {
1033410334
const signature = signatures[0];
10335-
if (!signature.typeParameters) {
10335+
if (!signature.typeParameters && !isAritySmaller(signature, node)) {
1033610336
return signature;
1033710337
}
1033810338
}
1033910339
}
1034010340

10341+
/** If the contextual signature has fewer parameters than the function expression, do not use it */
10342+
function isAritySmaller(signature: Signature, target: FunctionExpression | ArrowFunction | MethodDeclaration) {
10343+
let targetParameterCount = 0;
10344+
for (; targetParameterCount < target.parameters.length; targetParameterCount++) {
10345+
const param = target.parameters[targetParameterCount];
10346+
if (param.initializer || param.questionToken || param.dotDotDotToken || isJSDocOptionalParameter(param)) {
10347+
break;
10348+
}
10349+
}
10350+
if (target.parameters.length && parameterIsThisKeyword(target.parameters[0])) {
10351+
targetParameterCount--;
10352+
}
10353+
const sourceLength = signature.hasRestParameter ? Number.MAX_VALUE : signature.parameters.length;
10354+
return sourceLength < targetParameterCount;
10355+
}
10356+
1034110357
function isFunctionExpressionOrArrowFunction(node: Node): node is FunctionExpression | ArrowFunction {
1034210358
return node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.ArrowFunction;
1034310359
}
@@ -10367,12 +10383,12 @@ namespace ts {
1036710383
return undefined;
1036810384
}
1036910385
if (!(type.flags & TypeFlags.Union)) {
10370-
return getNonGenericSignature(type);
10386+
return getNonGenericSignature(type, node);
1037110387
}
1037210388
let signatureList: Signature[];
1037310389
const types = (<UnionType>type).types;
1037410390
for (const current of types) {
10375-
const signature = getNonGenericSignature(current);
10391+
const signature = getNonGenericSignature(current, node);
1037610392
if (signature) {
1037710393
if (!signatureList) {
1037810394
// This signature will contribute to contextual union signature
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//// [contextualTypingOfTooShortOverloads.ts]
2+
// small repro from #11875
3+
var use: Overload;
4+
use((req, res) => {});
5+
6+
interface Overload {
7+
(handler1: (req1: string) => void): void;
8+
(handler2: (req2: number, res2: number) => void): void;
9+
}
10+
// larger repro from #11875
11+
let app: MyApp;
12+
app.use((err: any, req, res, next) => { return; });
13+
14+
15+
interface MyApp {
16+
use: IRouterHandler<this> & IRouterMatcher<this>;
17+
}
18+
19+
interface IRouterHandler<T> {
20+
(...handlers: RequestHandler[]): T;
21+
(...handlers: RequestHandlerParams[]): T;
22+
}
23+
24+
interface IRouterMatcher<T> {
25+
(path: PathParams, ...handlers: RequestHandler[]): T;
26+
(path: PathParams, ...handlers: RequestHandlerParams[]): T;
27+
}
28+
29+
type PathParams = string | RegExp | (string | RegExp)[];
30+
type RequestHandlerParams = RequestHandler | ErrorRequestHandler | (RequestHandler | ErrorRequestHandler)[];
31+
32+
interface RequestHandler {
33+
(req: Request, res: Response, next: NextFunction): any;
34+
}
35+
36+
interface ErrorRequestHandler {
37+
(err: any, req: Request, res: Response, next: NextFunction): any;
38+
}
39+
40+
interface Request {
41+
method: string;
42+
}
43+
44+
interface Response {
45+
statusCode: number;
46+
}
47+
48+
interface NextFunction {
49+
(err?: any): void;
50+
}
51+
52+
53+
//// [contextualTypingOfTooShortOverloads.js]
54+
// small repro from #11875
55+
var use;
56+
use(function (req, res) { });
57+
// larger repro from #11875
58+
var app;
59+
app.use(function (err, req, res, next) { return; });
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
=== tests/cases/compiler/contextualTypingOfTooShortOverloads.ts ===
2+
// small repro from #11875
3+
var use: Overload;
4+
>use : Symbol(use, Decl(contextualTypingOfTooShortOverloads.ts, 1, 3))
5+
>Overload : Symbol(Overload, Decl(contextualTypingOfTooShortOverloads.ts, 2, 22))
6+
7+
use((req, res) => {});
8+
>use : Symbol(use, Decl(contextualTypingOfTooShortOverloads.ts, 1, 3))
9+
>req : Symbol(req, Decl(contextualTypingOfTooShortOverloads.ts, 2, 5))
10+
>res : Symbol(res, Decl(contextualTypingOfTooShortOverloads.ts, 2, 9))
11+
12+
interface Overload {
13+
>Overload : Symbol(Overload, Decl(contextualTypingOfTooShortOverloads.ts, 2, 22))
14+
15+
(handler1: (req1: string) => void): void;
16+
>handler1 : Symbol(handler1, Decl(contextualTypingOfTooShortOverloads.ts, 5, 5))
17+
>req1 : Symbol(req1, Decl(contextualTypingOfTooShortOverloads.ts, 5, 16))
18+
19+
(handler2: (req2: number, res2: number) => void): void;
20+
>handler2 : Symbol(handler2, Decl(contextualTypingOfTooShortOverloads.ts, 6, 5))
21+
>req2 : Symbol(req2, Decl(contextualTypingOfTooShortOverloads.ts, 6, 16))
22+
>res2 : Symbol(res2, Decl(contextualTypingOfTooShortOverloads.ts, 6, 29))
23+
}
24+
// larger repro from #11875
25+
let app: MyApp;
26+
>app : Symbol(app, Decl(contextualTypingOfTooShortOverloads.ts, 9, 3))
27+
>MyApp : Symbol(MyApp, Decl(contextualTypingOfTooShortOverloads.ts, 10, 51))
28+
29+
app.use((err: any, req, res, next) => { return; });
30+
>app.use : Symbol(MyApp.use, Decl(contextualTypingOfTooShortOverloads.ts, 13, 17))
31+
>app : Symbol(app, Decl(contextualTypingOfTooShortOverloads.ts, 9, 3))
32+
>use : Symbol(MyApp.use, Decl(contextualTypingOfTooShortOverloads.ts, 13, 17))
33+
>err : Symbol(err, Decl(contextualTypingOfTooShortOverloads.ts, 10, 9))
34+
>req : Symbol(req, Decl(contextualTypingOfTooShortOverloads.ts, 10, 18))
35+
>res : Symbol(res, Decl(contextualTypingOfTooShortOverloads.ts, 10, 23))
36+
>next : Symbol(next, Decl(contextualTypingOfTooShortOverloads.ts, 10, 28))
37+
38+
39+
interface MyApp {
40+
>MyApp : Symbol(MyApp, Decl(contextualTypingOfTooShortOverloads.ts, 10, 51))
41+
42+
use: IRouterHandler<this> & IRouterMatcher<this>;
43+
>use : Symbol(MyApp.use, Decl(contextualTypingOfTooShortOverloads.ts, 13, 17))
44+
>IRouterHandler : Symbol(IRouterHandler, Decl(contextualTypingOfTooShortOverloads.ts, 15, 1))
45+
>IRouterMatcher : Symbol(IRouterMatcher, Decl(contextualTypingOfTooShortOverloads.ts, 20, 1))
46+
}
47+
48+
interface IRouterHandler<T> {
49+
>IRouterHandler : Symbol(IRouterHandler, Decl(contextualTypingOfTooShortOverloads.ts, 15, 1))
50+
>T : Symbol(T, Decl(contextualTypingOfTooShortOverloads.ts, 17, 25))
51+
52+
(...handlers: RequestHandler[]): T;
53+
>handlers : Symbol(handlers, Decl(contextualTypingOfTooShortOverloads.ts, 18, 5))
54+
>RequestHandler : Symbol(RequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 28, 108))
55+
>T : Symbol(T, Decl(contextualTypingOfTooShortOverloads.ts, 17, 25))
56+
57+
(...handlers: RequestHandlerParams[]): T;
58+
>handlers : Symbol(handlers, Decl(contextualTypingOfTooShortOverloads.ts, 19, 5))
59+
>RequestHandlerParams : Symbol(RequestHandlerParams, Decl(contextualTypingOfTooShortOverloads.ts, 27, 56))
60+
>T : Symbol(T, Decl(contextualTypingOfTooShortOverloads.ts, 17, 25))
61+
}
62+
63+
interface IRouterMatcher<T> {
64+
>IRouterMatcher : Symbol(IRouterMatcher, Decl(contextualTypingOfTooShortOverloads.ts, 20, 1))
65+
>T : Symbol(T, Decl(contextualTypingOfTooShortOverloads.ts, 22, 25))
66+
67+
(path: PathParams, ...handlers: RequestHandler[]): T;
68+
>path : Symbol(path, Decl(contextualTypingOfTooShortOverloads.ts, 23, 5))
69+
>PathParams : Symbol(PathParams, Decl(contextualTypingOfTooShortOverloads.ts, 25, 1))
70+
>handlers : Symbol(handlers, Decl(contextualTypingOfTooShortOverloads.ts, 23, 22))
71+
>RequestHandler : Symbol(RequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 28, 108))
72+
>T : Symbol(T, Decl(contextualTypingOfTooShortOverloads.ts, 22, 25))
73+
74+
(path: PathParams, ...handlers: RequestHandlerParams[]): T;
75+
>path : Symbol(path, Decl(contextualTypingOfTooShortOverloads.ts, 24, 5))
76+
>PathParams : Symbol(PathParams, Decl(contextualTypingOfTooShortOverloads.ts, 25, 1))
77+
>handlers : Symbol(handlers, Decl(contextualTypingOfTooShortOverloads.ts, 24, 22))
78+
>RequestHandlerParams : Symbol(RequestHandlerParams, Decl(contextualTypingOfTooShortOverloads.ts, 27, 56))
79+
>T : Symbol(T, Decl(contextualTypingOfTooShortOverloads.ts, 22, 25))
80+
}
81+
82+
type PathParams = string | RegExp | (string | RegExp)[];
83+
>PathParams : Symbol(PathParams, Decl(contextualTypingOfTooShortOverloads.ts, 25, 1))
84+
>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
85+
>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
86+
87+
type RequestHandlerParams = RequestHandler | ErrorRequestHandler | (RequestHandler | ErrorRequestHandler)[];
88+
>RequestHandlerParams : Symbol(RequestHandlerParams, Decl(contextualTypingOfTooShortOverloads.ts, 27, 56))
89+
>RequestHandler : Symbol(RequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 28, 108))
90+
>ErrorRequestHandler : Symbol(ErrorRequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 32, 1))
91+
>RequestHandler : Symbol(RequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 28, 108))
92+
>ErrorRequestHandler : Symbol(ErrorRequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 32, 1))
93+
94+
interface RequestHandler {
95+
>RequestHandler : Symbol(RequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 28, 108))
96+
97+
(req: Request, res: Response, next: NextFunction): any;
98+
>req : Symbol(req, Decl(contextualTypingOfTooShortOverloads.ts, 31, 5))
99+
>Request : Symbol(Request, Decl(contextualTypingOfTooShortOverloads.ts, 36, 1))
100+
>res : Symbol(res, Decl(contextualTypingOfTooShortOverloads.ts, 31, 18))
101+
>Response : Symbol(Response, Decl(contextualTypingOfTooShortOverloads.ts, 40, 1))
102+
>next : Symbol(next, Decl(contextualTypingOfTooShortOverloads.ts, 31, 33))
103+
>NextFunction : Symbol(NextFunction, Decl(contextualTypingOfTooShortOverloads.ts, 44, 1))
104+
}
105+
106+
interface ErrorRequestHandler {
107+
>ErrorRequestHandler : Symbol(ErrorRequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 32, 1))
108+
109+
(err: any, req: Request, res: Response, next: NextFunction): any;
110+
>err : Symbol(err, Decl(contextualTypingOfTooShortOverloads.ts, 35, 5))
111+
>req : Symbol(req, Decl(contextualTypingOfTooShortOverloads.ts, 35, 14))
112+
>Request : Symbol(Request, Decl(contextualTypingOfTooShortOverloads.ts, 36, 1))
113+
>res : Symbol(res, Decl(contextualTypingOfTooShortOverloads.ts, 35, 28))
114+
>Response : Symbol(Response, Decl(contextualTypingOfTooShortOverloads.ts, 40, 1))
115+
>next : Symbol(next, Decl(contextualTypingOfTooShortOverloads.ts, 35, 43))
116+
>NextFunction : Symbol(NextFunction, Decl(contextualTypingOfTooShortOverloads.ts, 44, 1))
117+
}
118+
119+
interface Request {
120+
>Request : Symbol(Request, Decl(contextualTypingOfTooShortOverloads.ts, 36, 1))
121+
122+
method: string;
123+
>method : Symbol(Request.method, Decl(contextualTypingOfTooShortOverloads.ts, 38, 19))
124+
}
125+
126+
interface Response {
127+
>Response : Symbol(Response, Decl(contextualTypingOfTooShortOverloads.ts, 40, 1))
128+
129+
statusCode: number;
130+
>statusCode : Symbol(Response.statusCode, Decl(contextualTypingOfTooShortOverloads.ts, 42, 20))
131+
}
132+
133+
interface NextFunction {
134+
>NextFunction : Symbol(NextFunction, Decl(contextualTypingOfTooShortOverloads.ts, 44, 1))
135+
136+
(err?: any): void;
137+
>err : Symbol(err, Decl(contextualTypingOfTooShortOverloads.ts, 47, 5))
138+
}
139+
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
=== tests/cases/compiler/contextualTypingOfTooShortOverloads.ts ===
2+
// small repro from #11875
3+
var use: Overload;
4+
>use : Overload
5+
>Overload : Overload
6+
7+
use((req, res) => {});
8+
>use((req, res) => {}) : void
9+
>use : Overload
10+
>(req, res) => {} : (req: any, res: any) => void
11+
>req : any
12+
>res : any
13+
14+
interface Overload {
15+
>Overload : Overload
16+
17+
(handler1: (req1: string) => void): void;
18+
>handler1 : (req1: string) => void
19+
>req1 : string
20+
21+
(handler2: (req2: number, res2: number) => void): void;
22+
>handler2 : (req2: number, res2: number) => void
23+
>req2 : number
24+
>res2 : number
25+
}
26+
// larger repro from #11875
27+
let app: MyApp;
28+
>app : MyApp
29+
>MyApp : MyApp
30+
31+
app.use((err: any, req, res, next) => { return; });
32+
>app.use((err: any, req, res, next) => { return; }) : MyApp
33+
>app.use : IRouterHandler<MyApp> & IRouterMatcher<MyApp>
34+
>app : MyApp
35+
>use : IRouterHandler<MyApp> & IRouterMatcher<MyApp>
36+
>(err: any, req, res, next) => { return; } : (err: any, req: any, res: any, next: any) => void
37+
>err : any
38+
>req : any
39+
>res : any
40+
>next : any
41+
42+
43+
interface MyApp {
44+
>MyApp : MyApp
45+
46+
use: IRouterHandler<this> & IRouterMatcher<this>;
47+
>use : IRouterHandler<this> & IRouterMatcher<this>
48+
>IRouterHandler : IRouterHandler<T>
49+
>IRouterMatcher : IRouterMatcher<T>
50+
}
51+
52+
interface IRouterHandler<T> {
53+
>IRouterHandler : IRouterHandler<T>
54+
>T : T
55+
56+
(...handlers: RequestHandler[]): T;
57+
>handlers : RequestHandler[]
58+
>RequestHandler : RequestHandler
59+
>T : T
60+
61+
(...handlers: RequestHandlerParams[]): T;
62+
>handlers : RequestHandlerParams[]
63+
>RequestHandlerParams : RequestHandlerParams
64+
>T : T
65+
}
66+
67+
interface IRouterMatcher<T> {
68+
>IRouterMatcher : IRouterMatcher<T>
69+
>T : T
70+
71+
(path: PathParams, ...handlers: RequestHandler[]): T;
72+
>path : PathParams
73+
>PathParams : PathParams
74+
>handlers : RequestHandler[]
75+
>RequestHandler : RequestHandler
76+
>T : T
77+
78+
(path: PathParams, ...handlers: RequestHandlerParams[]): T;
79+
>path : PathParams
80+
>PathParams : PathParams
81+
>handlers : RequestHandlerParams[]
82+
>RequestHandlerParams : RequestHandlerParams
83+
>T : T
84+
}
85+
86+
type PathParams = string | RegExp | (string | RegExp)[];
87+
>PathParams : PathParams
88+
>RegExp : RegExp
89+
>RegExp : RegExp
90+
91+
type RequestHandlerParams = RequestHandler | ErrorRequestHandler | (RequestHandler | ErrorRequestHandler)[];
92+
>RequestHandlerParams : RequestHandlerParams
93+
>RequestHandler : RequestHandler
94+
>ErrorRequestHandler : ErrorRequestHandler
95+
>RequestHandler : RequestHandler
96+
>ErrorRequestHandler : ErrorRequestHandler
97+
98+
interface RequestHandler {
99+
>RequestHandler : RequestHandler
100+
101+
(req: Request, res: Response, next: NextFunction): any;
102+
>req : Request
103+
>Request : Request
104+
>res : Response
105+
>Response : Response
106+
>next : NextFunction
107+
>NextFunction : NextFunction
108+
}
109+
110+
interface ErrorRequestHandler {
111+
>ErrorRequestHandler : ErrorRequestHandler
112+
113+
(err: any, req: Request, res: Response, next: NextFunction): any;
114+
>err : any
115+
>req : Request
116+
>Request : Request
117+
>res : Response
118+
>Response : Response
119+
>next : NextFunction
120+
>NextFunction : NextFunction
121+
}
122+
123+
interface Request {
124+
>Request : Request
125+
126+
method: string;
127+
>method : string
128+
}
129+
130+
interface Response {
131+
>Response : Response
132+
133+
statusCode: number;
134+
>statusCode : number
135+
}
136+
137+
interface NextFunction {
138+
>NextFunction : NextFunction
139+
140+
(err?: any): void;
141+
>err : any
142+
}
143+

0 commit comments

Comments
 (0)