Skip to content

Treat ... in jsdoc type as creating a synthetic rest parameter -- not as an array type#19483

Merged
5 commits merged into
masterfrom
jsdocRestParameter
Nov 15, 2017
Merged

Treat ... in jsdoc type as creating a synthetic rest parameter -- not as an array type#19483
5 commits merged into
masterfrom
jsdocRestParameter

Conversation

@ghost
Copy link
Copy Markdown

@ghost ghost commented Oct 25, 2017

Fixes #19444
Breaking change if people are using ... types not in a rest parameter position -- those will be errors now.

@ghost ghost requested a review from sandersn October 25, 2017 22:27
!!! error TS8028: JSDoc '...' may only appear in the last parameter of a signature.
* @param {...number?[]!} k - (number[] | null)[]
~~~~~~~~~
!!! error TS8028: JSDoc '...' may only appear in the last parameter of a signature.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this is the last parameter of the signature.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, what is the error for repeated ellipses? It used to mean n-dimensional arrays, so it should definitely be an error now.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the error is because this is parsed as (((...number)?)!)[]. I've added a commit that changes the parser so that ... should be at the top level.

/** @param {...number} a */
function f(a) {
// Ideally this would be a number. But currently checker.ts has only one `argumentsSymbol`.
arguments[0];
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you show off the type of a somehow, eg with assignment to another number variable?

Comment thread src/compiler/checker.ts Outdated
const syntheticArgsSymbol = createSymbol(SymbolFlags.Variable, "args" as __String);
syntheticArgsSymbol.type = lastParamIsDocumentedAsRest ? createArrayType(getTypeOfParameter(lastParam.symbol)) : anyArrayType;
syntheticArgsSymbol.isRestParameter = true;
parameters.push(syntheticArgsSymbol);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will make f(a) have the signature f(a, ...Args)when the intent is just to have f(...Args). That is, the intent of jsdoc {...number} a is to replace a with ...args.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After thinking about it, the naive fix of replacing the actual symbol with the synthetic one is likely to cause problems with, eg, renaming a. So this code might be good enough. Do you mind checking how the naive fix behaves?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The real problem is, what will happen if the user tries to access a inside the body? Should we be giving them number | undefined because they declared it as a rest parameter?

@ghost ghost force-pushed the jsdocRestParameter branch from d8221fa to fc470ca Compare October 26, 2017 21:52
@ghost
Copy link
Copy Markdown
Author

ghost commented Oct 30, 2017

@sandersn Could you review again?

Copy link
Copy Markdown
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the new changes, I think we have pretty reasonable behaviour.

I also had a couple of style comments.

Comment thread src/compiler/checker.ts Outdated
getUnionType([type, undefinedType, nullType]);
}

function getUndefinedableType(type: Type): Type {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'undefinedable' is usually called 'optional' in our terminology

Comment thread src/compiler/checker.ts Outdated
syntheticArgsSymbol.type = lastParamIsDocumentedAsRest ? createArrayType(getTypeOfParameter(lastParam.symbol)) : anyArrayType;
syntheticArgsSymbol.type = lastParamVariadicType ? createArrayType(getTypeFromTypeNode(lastParamVariadicType.type)) : anyArrayType;
syntheticArgsSymbol.isRestParameter = true;
if (lastParamVariadicType) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just thinking aloud: About half of this code has a separate code path for lastParamVariadicType. Would it read better if the normal and last-param-variadic parts were separate?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this whole part out to its own function.

@ghost ghost merged commit 4b96edf into master Nov 15, 2017
@ghost ghost deleted the jsdocRestParameter branch November 15, 2017 21:04
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
This pull request was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant