-
Notifications
You must be signed in to change notification settings - Fork 12.8k
JSDoc @type tag optional parameters #48132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this basic approach is good enough, although it would be slightly more accurate to copy over the properties from signature
to a fresh signature whose symbol is the function value instead of the @type
annotation.
Why are there so many deleted baseline files? After that I think this will be ready to merge.
@@ -21,9 +21,9 @@ tests/cases/conformance/jsdoc/a.js(13,1): error TS2554: Expected 1 arguments, bu | |||
g() // should error | |||
~~~ | |||
!!! error TS2554: Expected 1 arguments, but got 0. | |||
!!! related TS6210 tests/cases/conformance/jsdoc/a.js:5:12: An argument for 's' was not provided. | |||
!!! related TS6210 tests/cases/conformance/jsdoc/a.js:4:13: An argument for 's' was not provided. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This error span change shows that re-using the signature isn't precisely correct. It's probably close enough, though, and it would take much more code to copy over the properties of the declared signature to the new signature.
This seems okay to fix the bug, but I'm not sure exactly if the changes in the diff are "good" or not. It seems like what's happening is that the declared parameter name (in the JS) is getting totally overridden by the jsdoc in the symbols output, which feels odd. I'm not sure what practical effect is has, though. |
111a593
to
7b85698
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jakebailey Thanks for reviewing!
- I rebased, which eliminated the unrelated, deleted baselines (they were for tests that no longer exist).
src/compiler/checker.ts
Outdated
@@ -12762,10 +12760,8 @@ namespace ts { | |||
} | |||
|
|||
function getSignatureFromDeclaration(declaration: SignatureDeclaration | JSDocSignature): Signature { | |||
if (isInJSFile(declaration)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed getSignatureOfTypeTag() already calls isInJSFile(), so I dropped that condition from this change, and from the other getSignatureOfTypeTag()/getParameterTypeOfTypeTag() call sites. It's a cosmetic change I'm happy to skip though, if you prefer?
@@ -20,7 +20,7 @@ var sid = s => s + "!"; | |||
/** @type {NoReturn} */ | |||
var noreturn = obj => void obj.title | |||
>noreturn : NoReturn | |||
>obj => void obj.title : (obj: { e: number; m: number; title: string; }) => any | |||
>obj => void obj.title : (s: { e: number; m: number; title: string; }) => any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These .types baselines are okay and expected, I think? We're now obeying the @type
tag, so the output is, e.g. the NoReturn
type, and the NoReturn
parameter name is s
.
5645d0d
to
eab90ca
Compare
5dd9a1b
to
f12b97f
Compare
I noticed that there's currently an error if an initializer isn't compatible with it's target, and that this PR was suppressing that, by applying
⏯️ Playground link🧑💻 Code// @checkJs
// @filename: input.js
// @errors: 2322 8030
// Confirm initializers are compatible.
// They can't have more parameters than the target.
/** @type {() => void} */
function func(more) {}
/** @type {() => void} */
const variable = function (more) {};
/** @type {() => void} */
const arrow = (more) => {};
({
/** @type {() => void} */
method(more) {},
/** @type {() => void} */
prop: function (more) {},
/** @type {() => void} */
arrow: (more) => {},
}); 📓 TILSome notes from exploring the code (not necessarily of benefit to anyone but myself):
|
efb13ef
to
5bb7079
Compare
Is this ready to review again? |
@sandersn Yes please. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good except for a couple of comment suggestions.
@@ -12941,7 +12939,15 @@ namespace ts { | |||
continue; | |||
} | |||
} | |||
result.push(getSignatureFromDeclaration(decl)); | |||
// If this is a function or method declaration, get the accurate minArgumentCount from the @type tag, if present. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// If this is a function or method declaration, get the accurate minArgumentCount from the @type tag, if present. | |
// If this is a function or method declaration, get the signature from the @type tag, if present. |
src/compiler/checker.ts
Outdated
// If this is a variable or property declaration, apply the @type tag to it | ||
// (getTypeForVariableLikeDeclaration()), not to the initializer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would delete this. I tried rewording and I got
// If this is a variable or property declaration, apply the @type tag to it | |
// (getTypeForVariableLikeDeclaration()), not to the initializer. | |
// other kinds are handled through contextual typing |
which is OK, but not that valuable to state explicitly. I'll leave it up to you whether you want to keep this, since I'm probably over-familiar with the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sandersn Thanks! I agree, as written the whole comment isn't that valuable ... I guess I was aiming to answer:
- Q: Why are we doing this for function and method declarations?
A: For optional parameters. - Q: Why are we excluding contextually-typed kinds?
A: Because they're already handled elsewhere, and not excluding them would suppress compatibility checks.
I've added a commit with an alternative rewording (based on your suggestions), but I'm very open to going with your preference!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I missed this until now. It's late enough in the 4.8 beta that I want to hold this for 4.9, so I'll merge it next week.
TS obeys JSDoc
@type
tag signatures, but not parameter optionality. Projects work around this by adding| void
to parameters in@type
tags, but this isn't strictly correct, and leads to problems later using those values, withoutExclude<param, void>
. e.g.🧐 Investigation
The signatures passed to
resolveCall()
ignore@type
tags entirely, so they have the wrongminArgumentCount
, sohasCorrectArity()
fails. I think they obey@param
tags?Otherwise, the applicability checks obey
@type
tags, becausegetSignatureApplicabilityError()
callsgetTypeAtPosition()
, which ... callsgetTypeForVariableLikeDeclaration()
, which contains:since #26694 (or #22692?).
Backing up,
resolveCallExpression()
callsresolveCall()
oncallSignatures
returned bygetSignaturesOfType()
(with the wrongminArgumentCount
).getSignaturesOfType()
calls ...getSignatureFromDeclaration()
, which obeys@param
tags, but not@type
tags?So maybe the solution is to (roughly) copy the
@type
tag logic fromgetTypeForVariableLikeDeclaration()
->getSignatureFromDeclaration()
? That's what I've tried to do in this PR.🔍 Search terms
jsdoc type tag optional parameters signature arity
🕗 Version & regression information
2.8.0-dev.20180320 - 4.7.0-dev.20220305
⏯️ Playground link
Workbench repro
🧑💻 Code
🙁 Actual behavior
🙂 Expected behavior
With this PR: