From 553d7271487ba13a22a9318fad86111348255df7 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 21 Jun 2016 13:01:26 -0700 Subject: [PATCH 1/2] Signatures use JSDoc to determine optionality --- src/compiler/checker.ts | 8 +-- ...signaturesUseJSDocForOptionalParameters.js | 32 +++++++++++ ...turesUseJSDocForOptionalParameters.symbols | 38 +++++++++++++ ...naturesUseJSDocForOptionalParameters.types | 53 +++++++++++++++++++ ...signaturesUseJSDocForOptionalParameters.ts | 17 ++++++ 5 files changed, 145 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/signaturesUseJSDocForOptionalParameters.js create mode 100644 tests/baselines/reference/signaturesUseJSDocForOptionalParameters.symbols create mode 100644 tests/baselines/reference/signaturesUseJSDocForOptionalParameters.types create mode 100644 tests/cases/compiler/signaturesUseJSDocForOptionalParameters.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ac8a47a9913..d083548242a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4397,7 +4397,7 @@ namespace ts { return result; } - function isOptionalParameter(node: ParameterDeclaration) { + function isJSDocOptionalParameter(node: ParameterDeclaration) { if (node.flags & NodeFlags.JavaScriptFile) { if (node.type && node.type.kind === SyntaxKind.JSDocOptionalType) { return true; @@ -4414,8 +4414,10 @@ namespace ts { } } } + } - if (hasQuestionToken(node)) { + function isOptionalParameter(node: ParameterDeclaration) { + if (isJSDocOptionalParameter(node) || hasQuestionToken(node)) { return true; } @@ -4482,7 +4484,7 @@ namespace ts { hasStringLiterals = true; } - if (param.initializer || param.questionToken || param.dotDotDotToken) { + if (param.initializer || param.questionToken || param.dotDotDotToken || isJSDocOptionalParameter(param)) { if (minArgumentCount < 0) { minArgumentCount = i - (hasThisParameter ? 1 : 0); } diff --git a/tests/baselines/reference/signaturesUseJSDocForOptionalParameters.js b/tests/baselines/reference/signaturesUseJSDocForOptionalParameters.js new file mode 100644 index 00000000000..b3d61a9f590 --- /dev/null +++ b/tests/baselines/reference/signaturesUseJSDocForOptionalParameters.js @@ -0,0 +1,32 @@ +//// [jsDocOptionality.js] +function MyClass() { + this.prop = null; +} +/** + * @param {string} required + * @param {string} [notRequired] + * @returns {MyClass} + */ +MyClass.prototype.optionalParam = function(required, notRequired) { + return this; +}; +let pInst = new MyClass(); +let c1 = pInst.optionalParam('hello') +let c2 = pInst.optionalParam('hello', null) + + +//// [out_1.js] +function MyClass() { + this.prop = null; +} +/** + * @param {string} required + * @param {string} [notRequired] + * @returns {MyClass} + */ +MyClass.prototype.optionalParam = function (required, notRequired) { + return this; +}; +var pInst = new MyClass(); +var c1 = pInst.optionalParam('hello'); +var c2 = pInst.optionalParam('hello', null); diff --git a/tests/baselines/reference/signaturesUseJSDocForOptionalParameters.symbols b/tests/baselines/reference/signaturesUseJSDocForOptionalParameters.symbols new file mode 100644 index 00000000000..5ea2756598e --- /dev/null +++ b/tests/baselines/reference/signaturesUseJSDocForOptionalParameters.symbols @@ -0,0 +1,38 @@ +=== tests/cases/compiler/jsDocOptionality.js === +function MyClass() { +>MyClass : Symbol(MyClass, Decl(jsDocOptionality.js, 0, 0)) + + this.prop = null; +>prop : Symbol(MyClass.prop, Decl(jsDocOptionality.js, 0, 20)) +} +/** + * @param {string} required + * @param {string} [notRequired] + * @returns {MyClass} + */ +MyClass.prototype.optionalParam = function(required, notRequired) { +>MyClass.prototype : Symbol(MyClass.optionalParam, Decl(jsDocOptionality.js, 2, 1)) +>MyClass : Symbol(MyClass, Decl(jsDocOptionality.js, 0, 0)) +>prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --)) +>optionalParam : Symbol(MyClass.optionalParam, Decl(jsDocOptionality.js, 2, 1)) +>required : Symbol(required, Decl(jsDocOptionality.js, 8, 43)) +>notRequired : Symbol(notRequired, Decl(jsDocOptionality.js, 8, 52)) + + return this; +}; +let pInst = new MyClass(); +>pInst : Symbol(pInst, Decl(jsDocOptionality.js, 11, 3)) +>MyClass : Symbol(MyClass, Decl(jsDocOptionality.js, 0, 0)) + +let c1 = pInst.optionalParam('hello') +>c1 : Symbol(c1, Decl(jsDocOptionality.js, 12, 3)) +>pInst.optionalParam : Symbol(MyClass.optionalParam, Decl(jsDocOptionality.js, 2, 1)) +>pInst : Symbol(pInst, Decl(jsDocOptionality.js, 11, 3)) +>optionalParam : Symbol(MyClass.optionalParam, Decl(jsDocOptionality.js, 2, 1)) + +let c2 = pInst.optionalParam('hello', null) +>c2 : Symbol(c2, Decl(jsDocOptionality.js, 13, 3)) +>pInst.optionalParam : Symbol(MyClass.optionalParam, Decl(jsDocOptionality.js, 2, 1)) +>pInst : Symbol(pInst, Decl(jsDocOptionality.js, 11, 3)) +>optionalParam : Symbol(MyClass.optionalParam, Decl(jsDocOptionality.js, 2, 1)) + diff --git a/tests/baselines/reference/signaturesUseJSDocForOptionalParameters.types b/tests/baselines/reference/signaturesUseJSDocForOptionalParameters.types new file mode 100644 index 00000000000..2dcaa37b947 --- /dev/null +++ b/tests/baselines/reference/signaturesUseJSDocForOptionalParameters.types @@ -0,0 +1,53 @@ +=== tests/cases/compiler/jsDocOptionality.js === +function MyClass() { +>MyClass : () => void + + this.prop = null; +>this.prop = null : null +>this.prop : any +>this : any +>prop : any +>null : null +} +/** + * @param {string} required + * @param {string} [notRequired] + * @returns {MyClass} + */ +MyClass.prototype.optionalParam = function(required, notRequired) { +>MyClass.prototype.optionalParam = function(required, notRequired) { return this;} : (required: string, notRequired?: string) => { prop: null; optionalParam: any; } +>MyClass.prototype.optionalParam : any +>MyClass.prototype : any +>MyClass : () => void +>prototype : any +>optionalParam : any +>function(required, notRequired) { return this;} : (required: string, notRequired?: string) => { prop: null; optionalParam: any; } +>required : string +>notRequired : string + + return this; +>this : { prop: null; optionalParam: (required: string, notRequired?: string) => { prop: null; optionalParam: any; }; } + +}; +let pInst = new MyClass(); +>pInst : { prop: null; optionalParam: (required: string, notRequired?: string) => { prop: null; optionalParam: any; }; } +>new MyClass() : { prop: null; optionalParam: (required: string, notRequired?: string) => { prop: null; optionalParam: any; }; } +>MyClass : () => void + +let c1 = pInst.optionalParam('hello') +>c1 : { prop: null; optionalParam: (required: string, notRequired?: string) => { prop: null; optionalParam: any; }; } +>pInst.optionalParam('hello') : { prop: null; optionalParam: (required: string, notRequired?: string) => { prop: null; optionalParam: any; }; } +>pInst.optionalParam : (required: string, notRequired?: string) => { prop: null; optionalParam: any; } +>pInst : { prop: null; optionalParam: (required: string, notRequired?: string) => { prop: null; optionalParam: any; }; } +>optionalParam : (required: string, notRequired?: string) => { prop: null; optionalParam: any; } +>'hello' : string + +let c2 = pInst.optionalParam('hello', null) +>c2 : { prop: null; optionalParam: (required: string, notRequired?: string) => { prop: null; optionalParam: any; }; } +>pInst.optionalParam('hello', null) : { prop: null; optionalParam: (required: string, notRequired?: string) => { prop: null; optionalParam: any; }; } +>pInst.optionalParam : (required: string, notRequired?: string) => { prop: null; optionalParam: any; } +>pInst : { prop: null; optionalParam: (required: string, notRequired?: string) => { prop: null; optionalParam: any; }; } +>optionalParam : (required: string, notRequired?: string) => { prop: null; optionalParam: any; } +>'hello' : string +>null : null + diff --git a/tests/cases/compiler/signaturesUseJSDocForOptionalParameters.ts b/tests/cases/compiler/signaturesUseJSDocForOptionalParameters.ts new file mode 100644 index 00000000000..a6f9c9fb394 --- /dev/null +++ b/tests/cases/compiler/signaturesUseJSDocForOptionalParameters.ts @@ -0,0 +1,17 @@ +// @allowJs: true +// @out: out_1.js +// @filename: jsDocOptionality.js +function MyClass() { + this.prop = null; +} +/** + * @param {string} required + * @param {string} [notRequired] + * @returns {MyClass} + */ +MyClass.prototype.optionalParam = function(required, notRequired) { + return this; +}; +let pInst = new MyClass(); +let c1 = pInst.optionalParam('hello') +let c2 = pInst.optionalParam('hello', null) From 3a7396ea1c5f17c414ea55051266746f15a857db Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 21 Jun 2016 15:55:55 -0700 Subject: [PATCH 2/2] For optionality, check question token before JSDoc --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d083548242a..b3f7c488ffb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4417,7 +4417,7 @@ namespace ts { } function isOptionalParameter(node: ParameterDeclaration) { - if (isJSDocOptionalParameter(node) || hasQuestionToken(node)) { + if (hasQuestionToken(node) || isJSDocOptionalParameter(node)) { return true; }