From 130adb53048e2cd598e8896ee7761192e9d4337e Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 2 Mar 2020 14:09:14 -0800 Subject: [PATCH] Preserve arity for preserving js optional parameters --- src/compiler/checker.ts | 11 +++++--- src/compiler/types.ts | 1 + .../jsDeclarationsClassLeadingOptional.js | 27 +++++++++++++++++++ ...jsDeclarationsClassLeadingOptional.symbols | 14 ++++++++++ .../jsDeclarationsClassLeadingOptional.types | 16 +++++++++++ .../jsDeclarationsClassLeadingOptional.ts | 11 ++++++++ 6 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/jsDeclarationsClassLeadingOptional.js create mode 100644 tests/baselines/reference/jsDeclarationsClassLeadingOptional.symbols create mode 100644 tests/baselines/reference/jsDeclarationsClassLeadingOptional.types create mode 100644 tests/cases/conformance/jsdoc/declarations/jsDeclarationsClassLeadingOptional.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 18d32322297f0..9bf94fa26fbc4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10499,7 +10499,7 @@ namespace ts { const signature = getSignatureFromDeclaration(node.parent); const parameterIndex = node.parent.parameters.indexOf(node); Debug.assert(parameterIndex >= 0); - return parameterIndex >= getMinArgumentCount(signature); + return parameterIndex >= getMinArgumentCount(signature, /*strongArityForUntypedJS*/ true); } const iife = getImmediatelyInvokedFunctionExpression(node.parent); if (iife) { @@ -10590,6 +10590,9 @@ namespace ts { isValueSignatureDeclaration(declaration) && !hasJSDocParameterTags(declaration) && !getJSDocType(declaration); + if (isUntypedSignatureInJSFile) { + flags |= SignatureFlags.IsUntypedSignatureInJSFile; + } // 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 @@ -10620,7 +10623,6 @@ namespace ts { const isOptionalParameter = isOptionalJSDocParameterTag(param) || param.initializer || param.questionToken || param.dotDotDotToken || iife && parameters.length > iife.arguments.length && !type || - isUntypedSignatureInJSFile || isJSDocOptionalParameter(param); if (!isOptionalParameter) { minArgumentCount = parameters.length; @@ -26340,7 +26342,7 @@ namespace ts { return length; } - function getMinArgumentCount(signature: Signature) { + function getMinArgumentCount(signature: Signature, strongArityForUntypedJS?: boolean) { if (signatureHasRestParameter(signature)) { const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); if (isTupleType(restType)) { @@ -26350,6 +26352,9 @@ namespace ts { } } } + if (!strongArityForUntypedJS && signature.flags & SignatureFlags.IsUntypedSignatureInJSFile) { + return 0; + } return signature.minArgumentCount; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 681e0837f0a7b..8e50b038f6a87 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4817,6 +4817,7 @@ namespace ts { HasLiteralTypes = 1 << 1, // Indicates signature is specialized IsInnerCallChain = 1 << 2, // Indicates signature comes from a CallChain nested in an outer OptionalChain IsOuterCallChain = 1 << 3, // Indicates signature comes from a CallChain that is the outermost chain of an optional expression + IsUntypedSignatureInJSFile = 1 << 4, // Indicates signature is from a js file and has no types // We do not propagate `IsInnerCallChain` to instantiated signatures, as that would result in us // attempting to add `| undefined` on each recursive call to `getReturnTypeOfSignature` when diff --git a/tests/baselines/reference/jsDeclarationsClassLeadingOptional.js b/tests/baselines/reference/jsDeclarationsClassLeadingOptional.js new file mode 100644 index 0000000000000..a53737c1f0d29 --- /dev/null +++ b/tests/baselines/reference/jsDeclarationsClassLeadingOptional.js @@ -0,0 +1,27 @@ +//// [bar.js] +export class Z { + f(x = 1, y) { + return [x, y]; + } +} + +//// [bar.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Z = void 0; +var Z = /** @class */ (function () { + function Z() { + } + Z.prototype.f = function (x, y) { + if (x === void 0) { x = 1; } + return [x, y]; + }; + return Z; +}()); +exports.Z = Z; + + +//// [bar.d.ts] +export class Z { + f(x: number, y: any): any[]; +} diff --git a/tests/baselines/reference/jsDeclarationsClassLeadingOptional.symbols b/tests/baselines/reference/jsDeclarationsClassLeadingOptional.symbols new file mode 100644 index 0000000000000..15087e370eb5c --- /dev/null +++ b/tests/baselines/reference/jsDeclarationsClassLeadingOptional.symbols @@ -0,0 +1,14 @@ +=== tests/cases/conformance/jsdoc/declarations/bar.js === +export class Z { +>Z : Symbol(Z, Decl(bar.js, 0, 0)) + + f(x = 1, y) { +>f : Symbol(Z.f, Decl(bar.js, 0, 16)) +>x : Symbol(x, Decl(bar.js, 1, 6)) +>y : Symbol(y, Decl(bar.js, 1, 12)) + + return [x, y]; +>x : Symbol(x, Decl(bar.js, 1, 6)) +>y : Symbol(y, Decl(bar.js, 1, 12)) + } +} diff --git a/tests/baselines/reference/jsDeclarationsClassLeadingOptional.types b/tests/baselines/reference/jsDeclarationsClassLeadingOptional.types new file mode 100644 index 0000000000000..2d4599e383648 --- /dev/null +++ b/tests/baselines/reference/jsDeclarationsClassLeadingOptional.types @@ -0,0 +1,16 @@ +=== tests/cases/conformance/jsdoc/declarations/bar.js === +export class Z { +>Z : Z + + f(x = 1, y) { +>f : (x: number, y: any) => any[] +>x : number +>1 : 1 +>y : any + + return [x, y]; +>[x, y] : any[] +>x : number +>y : any + } +} diff --git a/tests/cases/conformance/jsdoc/declarations/jsDeclarationsClassLeadingOptional.ts b/tests/cases/conformance/jsdoc/declarations/jsDeclarationsClassLeadingOptional.ts new file mode 100644 index 0000000000000..b3b27f096e9a9 --- /dev/null +++ b/tests/cases/conformance/jsdoc/declarations/jsDeclarationsClassLeadingOptional.ts @@ -0,0 +1,11 @@ +// @allowJs: true +// @checkJs: true +// @target: es5 +// @outDir: ./out +// @declaration: true +// @filename: bar.js +export class Z { + f(x = 1, y) { + return [x, y]; + } +} \ No newline at end of file