From 82a3feaadcfc1c5dedfdb982f8b817d78a2ba4e1 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Sun, 5 Feb 2017 15:18:27 -0800 Subject: [PATCH 1/3] Treat function paramters in a .js file with no JSDoc as optional --- src/compiler/checker.ts | 6 +++- ...jsFileFunctionParametersAsOptional.symbols | 22 +++++++++++++ .../jsFileFunctionParametersAsOptional.types | 32 +++++++++++++++++++ ...leFunctionParametersAsOptional2.errors.txt | 28 ++++++++++++++++ .../jsFileFunctionParametersAsOptional.ts | 12 +++++++ .../jsFileFunctionParametersAsOptional2.ts | 18 +++++++++++ 6 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/jsFileFunctionParametersAsOptional.symbols create mode 100644 tests/baselines/reference/jsFileFunctionParametersAsOptional.types create mode 100644 tests/baselines/reference/jsFileFunctionParametersAsOptional2.errors.txt create mode 100644 tests/cases/compiler/jsFileFunctionParametersAsOptional.ts create mode 100644 tests/cases/compiler/jsFileFunctionParametersAsOptional2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b5306771dd7..6b49b0bdb93 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5226,6 +5226,7 @@ namespace ts { let hasThisParameter: boolean; const iife = getImmediatelyInvokedFunctionExpression(declaration); const isJSConstructSignature = isJSDocConstructSignature(declaration); + const isUntypedSignatureInJSFile = !iife && !isJSConstructSignature && isInJavaScriptFile(declaration); // If this is a JSDoc construct signature, then skip the first parameter in the // parameter list. The first parameter represents the return type of the construct @@ -5251,10 +5252,13 @@ namespace ts { hasLiteralTypes = true; } + const isUntypedParamInJSFile = isUntypedSignatureInJSFile && !param.type && !getJSDocParameterTags(param); + // Record a new minimum argument count if this is not an optional parameter const isOptionalParameter = param.initializer || param.questionToken || param.dotDotDotToken || iife && parameters.length > iife.arguments.length && !param.type || - isJSDocOptionalParameter(param); + isJSDocOptionalParameter(param) || + isUntypedParamInJSFile; if (!isOptionalParameter) { minArgumentCount = parameters.length; } diff --git a/tests/baselines/reference/jsFileFunctionParametersAsOptional.symbols b/tests/baselines/reference/jsFileFunctionParametersAsOptional.symbols new file mode 100644 index 00000000000..040b910f378 --- /dev/null +++ b/tests/baselines/reference/jsFileFunctionParametersAsOptional.symbols @@ -0,0 +1,22 @@ +=== tests/cases/compiler/foo.js === + +function f(a, b, c) { } +>f : Symbol(f, Decl(foo.js, 0, 0)) +>a : Symbol(a, Decl(foo.js, 1, 11)) +>b : Symbol(b, Decl(foo.js, 1, 13)) +>c : Symbol(c, Decl(foo.js, 1, 16)) + + +=== tests/cases/compiler/bar.ts === +f(); +>f : Symbol(f, Decl(foo.js, 0, 0)) + +f(1); +>f : Symbol(f, Decl(foo.js, 0, 0)) + +f(1, 2); +>f : Symbol(f, Decl(foo.js, 0, 0)) + +f(1, 2, 3); +>f : Symbol(f, Decl(foo.js, 0, 0)) + diff --git a/tests/baselines/reference/jsFileFunctionParametersAsOptional.types b/tests/baselines/reference/jsFileFunctionParametersAsOptional.types new file mode 100644 index 00000000000..d6d8f9b04a4 --- /dev/null +++ b/tests/baselines/reference/jsFileFunctionParametersAsOptional.types @@ -0,0 +1,32 @@ +=== tests/cases/compiler/foo.js === + +function f(a, b, c) { } +>f : (a: any, b: any, c: any) => void +>a : any +>b : any +>c : any + + +=== tests/cases/compiler/bar.ts === +f(); +>f() : void +>f : (a: any, b: any, c: any) => void + +f(1); +>f(1) : void +>f : (a: any, b: any, c: any) => void +>1 : 1 + +f(1, 2); +>f(1, 2) : void +>f : (a: any, b: any, c: any) => void +>1 : 1 +>2 : 2 + +f(1, 2, 3); +>f(1, 2, 3) : void +>f : (a: any, b: any, c: any) => void +>1 : 1 +>2 : 2 +>3 : 3 + diff --git a/tests/baselines/reference/jsFileFunctionParametersAsOptional2.errors.txt b/tests/baselines/reference/jsFileFunctionParametersAsOptional2.errors.txt new file mode 100644 index 00000000000..26ada935eea --- /dev/null +++ b/tests/baselines/reference/jsFileFunctionParametersAsOptional2.errors.txt @@ -0,0 +1,28 @@ +tests/cases/compiler/bar.ts(1,1): error TS2346: Supplied parameters do not match any signature of call target. +tests/cases/compiler/bar.ts(2,1): error TS2346: Supplied parameters do not match any signature of call target. +tests/cases/compiler/bar.ts(3,1): error TS2346: Supplied parameters do not match any signature of call target. + + +==== tests/cases/compiler/foo.js (0 errors) ==== + + /** + * @param a + * @param b + * @param c + */ + function f(a, b, c) { } + + +==== tests/cases/compiler/bar.ts (3 errors) ==== + f(); // Error + ~~~ +!!! error TS2346: Supplied parameters do not match any signature of call target. + f(1); // Error + ~~~~ +!!! error TS2346: Supplied parameters do not match any signature of call target. + f(1, 2); // Error + ~~~~~~~ +!!! error TS2346: Supplied parameters do not match any signature of call target. + + f(1, 2, 3); // OK + \ No newline at end of file diff --git a/tests/cases/compiler/jsFileFunctionParametersAsOptional.ts b/tests/cases/compiler/jsFileFunctionParametersAsOptional.ts new file mode 100644 index 00000000000..f2673f310b8 --- /dev/null +++ b/tests/cases/compiler/jsFileFunctionParametersAsOptional.ts @@ -0,0 +1,12 @@ +// @allowJs: true +// @noEmit: true + +// @filename: foo.js +function f(a, b, c) { } + + +// @filename: bar.ts +f(); +f(1); +f(1, 2); +f(1, 2, 3); diff --git a/tests/cases/compiler/jsFileFunctionParametersAsOptional2.ts b/tests/cases/compiler/jsFileFunctionParametersAsOptional2.ts new file mode 100644 index 00000000000..01aebb29713 --- /dev/null +++ b/tests/cases/compiler/jsFileFunctionParametersAsOptional2.ts @@ -0,0 +1,18 @@ +// @allowJs: true +// @noEmit: true + +// @filename: foo.js +/** + * @param a + * @param b + * @param c + */ +function f(a, b, c) { } + + +// @filename: bar.ts +f(); // Error +f(1); // Error +f(1, 2); // Error + +f(1, 2, 3); // OK From a47c47611f6be54e86454a45e90bd89a270597fc Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 9 Feb 2017 15:25:49 -0800 Subject: [PATCH 2/3] Respond to code review comments --- src/compiler/checker.ts | 6 ++---- src/compiler/utilities.ts | 5 +++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6b49b0bdb93..88f4b1bfe6b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5226,7 +5226,7 @@ namespace ts { let hasThisParameter: boolean; const iife = getImmediatelyInvokedFunctionExpression(declaration); const isJSConstructSignature = isJSDocConstructSignature(declaration); - const isUntypedSignatureInJSFile = !iife && !isJSConstructSignature && isInJavaScriptFile(declaration); + const isUntypedSignatureInJSFile = !iife && !isJSConstructSignature && isInJavaScriptFile(declaration) && !hasJSDocParamterTags(declaration); // If this is a JSDoc construct signature, then skip the first parameter in the // parameter list. The first parameter represents the return type of the construct @@ -5252,13 +5252,11 @@ namespace ts { hasLiteralTypes = true; } - const isUntypedParamInJSFile = isUntypedSignatureInJSFile && !param.type && !getJSDocParameterTags(param); - // Record a new minimum argument count if this is not an optional parameter const isOptionalParameter = param.initializer || param.questionToken || param.dotDotDotToken || iife && parameters.length > iife.arguments.length && !param.type || isJSDocOptionalParameter(param) || - isUntypedParamInJSFile; + isUntypedSignatureInJSFile; if (!isOptionalParameter) { minArgumentCount = parameters.length; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 01cfcb08047..9935c2fb849 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1518,6 +1518,11 @@ namespace ts { return map(getJSDocs(node), doc => doc.comment); } + export function hasJSDocParamterTags(node: FunctionLikeDeclaration | SignatureDeclaration) { + const parameterTags = getJSDocTags(node, SyntaxKind.JSDocParameterTag); + return parameterTags && parameterTags.length > 0; + } + function getJSDocTags(node: Node, kind: SyntaxKind): JSDocTag[] { const docs = getJSDocs(node); if (docs) { From e76607e8649d86d6fba3342345f6fb020501bc96 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 9 Feb 2017 16:24:32 -0800 Subject: [PATCH 3/3] Fix typo --- src/compiler/checker.ts | 2 +- src/compiler/utilities.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 88f4b1bfe6b..62b761cae5b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5226,7 +5226,7 @@ namespace ts { let hasThisParameter: boolean; const iife = getImmediatelyInvokedFunctionExpression(declaration); const isJSConstructSignature = isJSDocConstructSignature(declaration); - const isUntypedSignatureInJSFile = !iife && !isJSConstructSignature && isInJavaScriptFile(declaration) && !hasJSDocParamterTags(declaration); + const isUntypedSignatureInJSFile = !iife && !isJSConstructSignature && isInJavaScriptFile(declaration) && !hasJSDocParameterTags(declaration); // If this is a JSDoc construct signature, then skip the first parameter in the // parameter list. The first parameter represents the return type of the construct diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 9935c2fb849..7d6d93c3c4e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1518,7 +1518,7 @@ namespace ts { return map(getJSDocs(node), doc => doc.comment); } - export function hasJSDocParamterTags(node: FunctionLikeDeclaration | SignatureDeclaration) { + export function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration) { const parameterTags = getJSDocTags(node, SyntaxKind.JSDocParameterTag); return parameterTags && parameterTags.length > 0; }