Merge pull request #11905 from Microsoft/skip-overloads-with-too-short-function-parameters

Skip overloads with too short function parameters
This commit is contained in:
Nathan Shively-Sanders 2016-10-28 09:59:38 -07:00 committed by GitHub
commit fdcc7cc185
6 changed files with 416 additions and 10 deletions

View File

@ -10328,16 +10328,32 @@ namespace ts {
// If the given type is an object or union type, if that type has a single signature, and if
// that signature is non-generic, return the signature. Otherwise return undefined.
function getNonGenericSignature(type: Type): Signature {
function getNonGenericSignature(type: Type, node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature {
const signatures = getSignaturesOfStructuredType(type, SignatureKind.Call);
if (signatures.length === 1) {
const signature = signatures[0];
if (!signature.typeParameters) {
if (!signature.typeParameters && !isAritySmaller(signature, node)) {
return signature;
}
}
}
/** If the contextual signature has fewer parameters than the function expression, do not use it */
function isAritySmaller(signature: Signature, target: FunctionExpression | ArrowFunction | MethodDeclaration) {
let targetParameterCount = 0;
for (; targetParameterCount < target.parameters.length; targetParameterCount++) {
const param = target.parameters[targetParameterCount];
if (param.initializer || param.questionToken || param.dotDotDotToken || isJSDocOptionalParameter(param)) {
break;
}
}
if (target.parameters.length && parameterIsThisKeyword(target.parameters[0])) {
targetParameterCount--;
}
const sourceLength = signature.hasRestParameter ? Number.MAX_VALUE : signature.parameters.length;
return sourceLength < targetParameterCount;
}
function isFunctionExpressionOrArrowFunction(node: Node): node is FunctionExpression | ArrowFunction {
return node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.ArrowFunction;
}
@ -10367,12 +10383,12 @@ namespace ts {
return undefined;
}
if (!(type.flags & TypeFlags.Union)) {
return getNonGenericSignature(type);
return getNonGenericSignature(type, node);
}
let signatureList: Signature[];
const types = (<UnionType>type).types;
for (const current of types) {
const signature = getNonGenericSignature(current);
const signature = getNonGenericSignature(current, node);
if (signature) {
if (!signatureList) {
// This signature will contribute to contextual union signature

View File

@ -0,0 +1,59 @@
//// [contextualTypingOfTooShortOverloads.ts]
// small repro from #11875
var use: Overload;
use((req, res) => {});
interface Overload {
(handler1: (req1: string) => void): void;
(handler2: (req2: number, res2: number) => void): void;
}
// larger repro from #11875
let app: MyApp;
app.use((err: any, req, res, next) => { return; });
interface MyApp {
use: IRouterHandler<this> & IRouterMatcher<this>;
}
interface IRouterHandler<T> {
(...handlers: RequestHandler[]): T;
(...handlers: RequestHandlerParams[]): T;
}
interface IRouterMatcher<T> {
(path: PathParams, ...handlers: RequestHandler[]): T;
(path: PathParams, ...handlers: RequestHandlerParams[]): T;
}
type PathParams = string | RegExp | (string | RegExp)[];
type RequestHandlerParams = RequestHandler | ErrorRequestHandler | (RequestHandler | ErrorRequestHandler)[];
interface RequestHandler {
(req: Request, res: Response, next: NextFunction): any;
}
interface ErrorRequestHandler {
(err: any, req: Request, res: Response, next: NextFunction): any;
}
interface Request {
method: string;
}
interface Response {
statusCode: number;
}
interface NextFunction {
(err?: any): void;
}
//// [contextualTypingOfTooShortOverloads.js]
// small repro from #11875
var use;
use(function (req, res) { });
// larger repro from #11875
var app;
app.use(function (err, req, res, next) { return; });

View File

@ -0,0 +1,139 @@
=== tests/cases/compiler/contextualTypingOfTooShortOverloads.ts ===
// small repro from #11875
var use: Overload;
>use : Symbol(use, Decl(contextualTypingOfTooShortOverloads.ts, 1, 3))
>Overload : Symbol(Overload, Decl(contextualTypingOfTooShortOverloads.ts, 2, 22))
use((req, res) => {});
>use : Symbol(use, Decl(contextualTypingOfTooShortOverloads.ts, 1, 3))
>req : Symbol(req, Decl(contextualTypingOfTooShortOverloads.ts, 2, 5))
>res : Symbol(res, Decl(contextualTypingOfTooShortOverloads.ts, 2, 9))
interface Overload {
>Overload : Symbol(Overload, Decl(contextualTypingOfTooShortOverloads.ts, 2, 22))
(handler1: (req1: string) => void): void;
>handler1 : Symbol(handler1, Decl(contextualTypingOfTooShortOverloads.ts, 5, 5))
>req1 : Symbol(req1, Decl(contextualTypingOfTooShortOverloads.ts, 5, 16))
(handler2: (req2: number, res2: number) => void): void;
>handler2 : Symbol(handler2, Decl(contextualTypingOfTooShortOverloads.ts, 6, 5))
>req2 : Symbol(req2, Decl(contextualTypingOfTooShortOverloads.ts, 6, 16))
>res2 : Symbol(res2, Decl(contextualTypingOfTooShortOverloads.ts, 6, 29))
}
// larger repro from #11875
let app: MyApp;
>app : Symbol(app, Decl(contextualTypingOfTooShortOverloads.ts, 9, 3))
>MyApp : Symbol(MyApp, Decl(contextualTypingOfTooShortOverloads.ts, 10, 51))
app.use((err: any, req, res, next) => { return; });
>app.use : Symbol(MyApp.use, Decl(contextualTypingOfTooShortOverloads.ts, 13, 17))
>app : Symbol(app, Decl(contextualTypingOfTooShortOverloads.ts, 9, 3))
>use : Symbol(MyApp.use, Decl(contextualTypingOfTooShortOverloads.ts, 13, 17))
>err : Symbol(err, Decl(contextualTypingOfTooShortOverloads.ts, 10, 9))
>req : Symbol(req, Decl(contextualTypingOfTooShortOverloads.ts, 10, 18))
>res : Symbol(res, Decl(contextualTypingOfTooShortOverloads.ts, 10, 23))
>next : Symbol(next, Decl(contextualTypingOfTooShortOverloads.ts, 10, 28))
interface MyApp {
>MyApp : Symbol(MyApp, Decl(contextualTypingOfTooShortOverloads.ts, 10, 51))
use: IRouterHandler<this> & IRouterMatcher<this>;
>use : Symbol(MyApp.use, Decl(contextualTypingOfTooShortOverloads.ts, 13, 17))
>IRouterHandler : Symbol(IRouterHandler, Decl(contextualTypingOfTooShortOverloads.ts, 15, 1))
>IRouterMatcher : Symbol(IRouterMatcher, Decl(contextualTypingOfTooShortOverloads.ts, 20, 1))
}
interface IRouterHandler<T> {
>IRouterHandler : Symbol(IRouterHandler, Decl(contextualTypingOfTooShortOverloads.ts, 15, 1))
>T : Symbol(T, Decl(contextualTypingOfTooShortOverloads.ts, 17, 25))
(...handlers: RequestHandler[]): T;
>handlers : Symbol(handlers, Decl(contextualTypingOfTooShortOverloads.ts, 18, 5))
>RequestHandler : Symbol(RequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 28, 108))
>T : Symbol(T, Decl(contextualTypingOfTooShortOverloads.ts, 17, 25))
(...handlers: RequestHandlerParams[]): T;
>handlers : Symbol(handlers, Decl(contextualTypingOfTooShortOverloads.ts, 19, 5))
>RequestHandlerParams : Symbol(RequestHandlerParams, Decl(contextualTypingOfTooShortOverloads.ts, 27, 56))
>T : Symbol(T, Decl(contextualTypingOfTooShortOverloads.ts, 17, 25))
}
interface IRouterMatcher<T> {
>IRouterMatcher : Symbol(IRouterMatcher, Decl(contextualTypingOfTooShortOverloads.ts, 20, 1))
>T : Symbol(T, Decl(contextualTypingOfTooShortOverloads.ts, 22, 25))
(path: PathParams, ...handlers: RequestHandler[]): T;
>path : Symbol(path, Decl(contextualTypingOfTooShortOverloads.ts, 23, 5))
>PathParams : Symbol(PathParams, Decl(contextualTypingOfTooShortOverloads.ts, 25, 1))
>handlers : Symbol(handlers, Decl(contextualTypingOfTooShortOverloads.ts, 23, 22))
>RequestHandler : Symbol(RequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 28, 108))
>T : Symbol(T, Decl(contextualTypingOfTooShortOverloads.ts, 22, 25))
(path: PathParams, ...handlers: RequestHandlerParams[]): T;
>path : Symbol(path, Decl(contextualTypingOfTooShortOverloads.ts, 24, 5))
>PathParams : Symbol(PathParams, Decl(contextualTypingOfTooShortOverloads.ts, 25, 1))
>handlers : Symbol(handlers, Decl(contextualTypingOfTooShortOverloads.ts, 24, 22))
>RequestHandlerParams : Symbol(RequestHandlerParams, Decl(contextualTypingOfTooShortOverloads.ts, 27, 56))
>T : Symbol(T, Decl(contextualTypingOfTooShortOverloads.ts, 22, 25))
}
type PathParams = string | RegExp | (string | RegExp)[];
>PathParams : Symbol(PathParams, Decl(contextualTypingOfTooShortOverloads.ts, 25, 1))
>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
type RequestHandlerParams = RequestHandler | ErrorRequestHandler | (RequestHandler | ErrorRequestHandler)[];
>RequestHandlerParams : Symbol(RequestHandlerParams, Decl(contextualTypingOfTooShortOverloads.ts, 27, 56))
>RequestHandler : Symbol(RequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 28, 108))
>ErrorRequestHandler : Symbol(ErrorRequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 32, 1))
>RequestHandler : Symbol(RequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 28, 108))
>ErrorRequestHandler : Symbol(ErrorRequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 32, 1))
interface RequestHandler {
>RequestHandler : Symbol(RequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 28, 108))
(req: Request, res: Response, next: NextFunction): any;
>req : Symbol(req, Decl(contextualTypingOfTooShortOverloads.ts, 31, 5))
>Request : Symbol(Request, Decl(contextualTypingOfTooShortOverloads.ts, 36, 1))
>res : Symbol(res, Decl(contextualTypingOfTooShortOverloads.ts, 31, 18))
>Response : Symbol(Response, Decl(contextualTypingOfTooShortOverloads.ts, 40, 1))
>next : Symbol(next, Decl(contextualTypingOfTooShortOverloads.ts, 31, 33))
>NextFunction : Symbol(NextFunction, Decl(contextualTypingOfTooShortOverloads.ts, 44, 1))
}
interface ErrorRequestHandler {
>ErrorRequestHandler : Symbol(ErrorRequestHandler, Decl(contextualTypingOfTooShortOverloads.ts, 32, 1))
(err: any, req: Request, res: Response, next: NextFunction): any;
>err : Symbol(err, Decl(contextualTypingOfTooShortOverloads.ts, 35, 5))
>req : Symbol(req, Decl(contextualTypingOfTooShortOverloads.ts, 35, 14))
>Request : Symbol(Request, Decl(contextualTypingOfTooShortOverloads.ts, 36, 1))
>res : Symbol(res, Decl(contextualTypingOfTooShortOverloads.ts, 35, 28))
>Response : Symbol(Response, Decl(contextualTypingOfTooShortOverloads.ts, 40, 1))
>next : Symbol(next, Decl(contextualTypingOfTooShortOverloads.ts, 35, 43))
>NextFunction : Symbol(NextFunction, Decl(contextualTypingOfTooShortOverloads.ts, 44, 1))
}
interface Request {
>Request : Symbol(Request, Decl(contextualTypingOfTooShortOverloads.ts, 36, 1))
method: string;
>method : Symbol(Request.method, Decl(contextualTypingOfTooShortOverloads.ts, 38, 19))
}
interface Response {
>Response : Symbol(Response, Decl(contextualTypingOfTooShortOverloads.ts, 40, 1))
statusCode: number;
>statusCode : Symbol(Response.statusCode, Decl(contextualTypingOfTooShortOverloads.ts, 42, 20))
}
interface NextFunction {
>NextFunction : Symbol(NextFunction, Decl(contextualTypingOfTooShortOverloads.ts, 44, 1))
(err?: any): void;
>err : Symbol(err, Decl(contextualTypingOfTooShortOverloads.ts, 47, 5))
}

View File

@ -0,0 +1,143 @@
=== tests/cases/compiler/contextualTypingOfTooShortOverloads.ts ===
// small repro from #11875
var use: Overload;
>use : Overload
>Overload : Overload
use((req, res) => {});
>use((req, res) => {}) : void
>use : Overload
>(req, res) => {} : (req: any, res: any) => void
>req : any
>res : any
interface Overload {
>Overload : Overload
(handler1: (req1: string) => void): void;
>handler1 : (req1: string) => void
>req1 : string
(handler2: (req2: number, res2: number) => void): void;
>handler2 : (req2: number, res2: number) => void
>req2 : number
>res2 : number
}
// larger repro from #11875
let app: MyApp;
>app : MyApp
>MyApp : MyApp
app.use((err: any, req, res, next) => { return; });
>app.use((err: any, req, res, next) => { return; }) : MyApp
>app.use : IRouterHandler<MyApp> & IRouterMatcher<MyApp>
>app : MyApp
>use : IRouterHandler<MyApp> & IRouterMatcher<MyApp>
>(err: any, req, res, next) => { return; } : (err: any, req: any, res: any, next: any) => void
>err : any
>req : any
>res : any
>next : any
interface MyApp {
>MyApp : MyApp
use: IRouterHandler<this> & IRouterMatcher<this>;
>use : IRouterHandler<this> & IRouterMatcher<this>
>IRouterHandler : IRouterHandler<T>
>IRouterMatcher : IRouterMatcher<T>
}
interface IRouterHandler<T> {
>IRouterHandler : IRouterHandler<T>
>T : T
(...handlers: RequestHandler[]): T;
>handlers : RequestHandler[]
>RequestHandler : RequestHandler
>T : T
(...handlers: RequestHandlerParams[]): T;
>handlers : RequestHandlerParams[]
>RequestHandlerParams : RequestHandlerParams
>T : T
}
interface IRouterMatcher<T> {
>IRouterMatcher : IRouterMatcher<T>
>T : T
(path: PathParams, ...handlers: RequestHandler[]): T;
>path : PathParams
>PathParams : PathParams
>handlers : RequestHandler[]
>RequestHandler : RequestHandler
>T : T
(path: PathParams, ...handlers: RequestHandlerParams[]): T;
>path : PathParams
>PathParams : PathParams
>handlers : RequestHandlerParams[]
>RequestHandlerParams : RequestHandlerParams
>T : T
}
type PathParams = string | RegExp | (string | RegExp)[];
>PathParams : PathParams
>RegExp : RegExp
>RegExp : RegExp
type RequestHandlerParams = RequestHandler | ErrorRequestHandler | (RequestHandler | ErrorRequestHandler)[];
>RequestHandlerParams : RequestHandlerParams
>RequestHandler : RequestHandler
>ErrorRequestHandler : ErrorRequestHandler
>RequestHandler : RequestHandler
>ErrorRequestHandler : ErrorRequestHandler
interface RequestHandler {
>RequestHandler : RequestHandler
(req: Request, res: Response, next: NextFunction): any;
>req : Request
>Request : Request
>res : Response
>Response : Response
>next : NextFunction
>NextFunction : NextFunction
}
interface ErrorRequestHandler {
>ErrorRequestHandler : ErrorRequestHandler
(err: any, req: Request, res: Response, next: NextFunction): any;
>err : any
>req : Request
>Request : Request
>res : Response
>Response : Response
>next : NextFunction
>NextFunction : NextFunction
}
interface Request {
>Request : Request
method: string;
>method : string
}
interface Response {
>Response : Response
statusCode: number;
>statusCode : number
}
interface NextFunction {
>NextFunction : NextFunction
(err?: any): void;
>err : any
}

View File

@ -1,6 +1,6 @@
tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts(12,11): error TS2345: Argument of type '(t1: D, t2: D, t3: any) => void' is not assignable to parameter of type '(t: D, t1: D) => void'.
tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts(13,11): error TS2345: Argument of type '(t1: D, t2: D, t3: any) => void' is not assignable to parameter of type '(t: D, t1: D) => void'.
tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts(14,11): error TS2345: Argument of type '(t1: C, t2: C, t3: D) => void' is not assignable to parameter of type '(t: C, t1: C) => void'.
tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts(12,11): error TS2345: Argument of type '(t1: D, t2: any, t3: any) => void' is not assignable to parameter of type '(t: any, t1: any) => void'.
tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts(13,11): error TS2345: Argument of type '(t1: any, t2: D, t3: any) => void' is not assignable to parameter of type '(t: any, t1: any) => void'.
tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts(14,11): error TS2345: Argument of type '(t1: any, t2: any, t3: D) => void' is not assignable to parameter of type '(t: any, t1: any) => void'.
==== tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partiallyAnnotatedFunctionInferenceError.ts (3 errors) ====
@ -17,11 +17,11 @@ tests/cases/conformance/types/contextualTypes/partiallyAnnotatedFunction/partial
// more args
testError((t1: D, t2, t3) => {})
~~~~~~~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type '(t1: D, t2: D, t3: any) => void' is not assignable to parameter of type '(t: D, t1: D) => void'.
!!! error TS2345: Argument of type '(t1: D, t2: any, t3: any) => void' is not assignable to parameter of type '(t: any, t1: any) => void'.
testError((t1, t2: D, t3) => {})
~~~~~~~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type '(t1: D, t2: D, t3: any) => void' is not assignable to parameter of type '(t: D, t1: D) => void'.
!!! error TS2345: Argument of type '(t1: any, t2: D, t3: any) => void' is not assignable to parameter of type '(t: any, t1: any) => void'.
testError((t1, t2, t3: D) => {})
~~~~~~~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type '(t1: C, t2: C, t3: D) => void' is not assignable to parameter of type '(t: C, t1: C) => void'.
!!! error TS2345: Argument of type '(t1: any, t2: any, t3: D) => void' is not assignable to parameter of type '(t: any, t1: any) => void'.

View File

@ -0,0 +1,49 @@
// small repro from #11875
var use: Overload;
use((req, res) => {});
interface Overload {
(handler1: (req1: string) => void): void;
(handler2: (req2: number, res2: number) => void): void;
}
// larger repro from #11875
let app: MyApp;
app.use((err: any, req, res, next) => { return; });
interface MyApp {
use: IRouterHandler<this> & IRouterMatcher<this>;
}
interface IRouterHandler<T> {
(...handlers: RequestHandler[]): T;
(...handlers: RequestHandlerParams[]): T;
}
interface IRouterMatcher<T> {
(path: PathParams, ...handlers: RequestHandler[]): T;
(path: PathParams, ...handlers: RequestHandlerParams[]): T;
}
type PathParams = string | RegExp | (string | RegExp)[];
type RequestHandlerParams = RequestHandler | ErrorRequestHandler | (RequestHandler | ErrorRequestHandler)[];
interface RequestHandler {
(req: Request, res: Response, next: NextFunction): any;
}
interface ErrorRequestHandler {
(err: any, req: Request, res: Response, next: NextFunction): any;
}
interface Request {
method: string;
}
interface Response {
statusCode: number;
}
interface NextFunction {
(err?: any): void;
}