JSDoc overload tag (#51234)

* Add support for JSDocOverloadTag

* Use overload tag to determine function type

* Update baselines

* Add new tests along with baselines

* Add tests for all @overload tags in one comment

* Add tests for find-all-ref and rename operations

* Add tests for alternative uses of @overload tag

Co-authored-by: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com>
This commit is contained in:
Tomasz Lenarcik 2022-12-14 00:10:40 +01:00 committed by GitHub
parent 4076ff8fd6
commit e4816ed44c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 1979 additions and 46 deletions

View File

@ -220,6 +220,7 @@ import {
JSDocClassTag,
JSDocEnumTag,
JSDocFunctionType,
JSDocOverloadTag,
JSDocParameterTag,
JSDocPropertyLikeTag,
JSDocSignature,
@ -2966,6 +2967,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
case SyntaxKind.JSDocCallbackTag:
case SyntaxKind.JSDocEnumTag:
return (delayedTypeAliases || (delayedTypeAliases = [])).push(node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag);
case SyntaxKind.JSDocOverloadTag:
return bind((node as JSDocOverloadTag).typeExpression);
}
}

View File

@ -549,6 +549,7 @@ import {
isJSDocNullableType,
isJSDocOptionalParameter,
isJSDocOptionalType,
isJSDocOverloadTag,
isJSDocParameterTag,
isJSDocPropertyLikeTag,
isJSDocPropertyTag,
@ -14270,6 +14271,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
continue;
}
}
if (isInJSFile(decl) && decl.jsDoc) {
let hasJSDocOverloads = false;
for (const node of decl.jsDoc) {
if (node.tags) {
for (const tag of node.tags) {
if (isJSDocOverloadTag(tag)) {
result.push(getSignatureFromDeclaration(tag.typeExpression));
hasJSDocOverloads = true;
}
}
}
}
if (hasJSDocOverloads) {
continue;
}
}
// If this is a function or method declaration, get the signature from the @type tag for the sake of optional parameters.
// Exclude contextually-typed kinds because we already apply the @type tag to the context, plus applying it here to the initializer would supress checks that the two are compatible.
result.push(

View File

@ -261,6 +261,7 @@ import {
JSDocNonNullableType,
JSDocNullableType,
JSDocOptionalType,
JSDocOverloadTag,
JSDocPropertyLikeTag,
JSDocReturnTag,
JSDocSeeTag,
@ -2117,6 +2118,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
return;
case SyntaxKind.JSDocCallbackTag:
return emitJSDocCallbackTag(node as JSDocCallbackTag);
case SyntaxKind.JSDocOverloadTag:
return emitJSDocOverloadTag(node as JSDocOverloadTag);
// SyntaxKind.JSDocEnumTag (see below)
case SyntaxKind.JSDocParameterTag:
case SyntaxKind.JSDocPropertyTag:
@ -4375,6 +4378,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
emitJSDocSignature(tag.typeExpression);
}
function emitJSDocOverloadTag(tag: JSDocOverloadTag) {
emitJSDocComment(tag.comment);
emitJSDocSignature(tag.typeExpression);
}
function emitJSDocSimpleTag(tag: JSDocTag) {
emitJSDocTagName(tag.tagName);
emitJSDocComment(tag.comment);

View File

@ -239,6 +239,7 @@ import {
JSDocNonNullableType,
JSDocNullableType,
JSDocOptionalType,
JSDocOverloadTag,
JSDocOverrideTag,
JSDocParameterTag,
JSDocPrivateTag,
@ -830,6 +831,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
updateJSDocPropertyTag,
createJSDocCallbackTag,
updateJSDocCallbackTag,
createJSDocOverloadTag,
updateJSDocOverloadTag,
createJSDocAugmentsTag,
updateJSDocAugmentsTag,
createJSDocImplementsTag,
@ -5305,6 +5308,22 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
: node;
}
// @api
function createJSDocOverloadTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, comment?: string | NodeArray<JSDocComment>): JSDocOverloadTag {
const node = createBaseJSDocTag<JSDocOverloadTag>(SyntaxKind.JSDocOverloadTag, tagName ?? createIdentifier("overload"), comment);
node.typeExpression = typeExpression;
return node;
}
// @api
function updateJSDocOverloadTag(node: JSDocOverloadTag, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocSignature, comment: string | NodeArray<JSDocComment> | undefined): JSDocOverloadTag {
return node.tagName !== tagName
|| node.typeExpression !== typeExpression
|| node.comment !== comment
? update(createJSDocOverloadTag(tagName, typeExpression, comment), node)
: node;
}
// @api
function createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocAugmentsTag {
const node = createBaseJSDocTag<JSDocAugmentsTag>(SyntaxKind.JSDocAugmentsTag, tagName ?? createIdentifier("augments"), comment);
@ -7193,6 +7212,7 @@ function getDefaultTagNameForKind(kind: JSDocTag["kind"]): string {
case SyntaxKind.JSDocParameterTag: return "param";
case SyntaxKind.JSDocPropertyTag: return "prop";
case SyntaxKind.JSDocCallbackTag: return "callback";
case SyntaxKind.JSDocOverloadTag: return "overload";
case SyntaxKind.JSDocAugmentsTag: return "augments";
case SyntaxKind.JSDocImplementsTag: return "implements";
default:

View File

@ -98,6 +98,7 @@ import {
JSDocNonNullableType,
JSDocNullableType,
JSDocOptionalType,
JSDocOverloadTag,
JSDocOverrideTag,
JSDocParameterTag,
JSDocPrivateTag,
@ -1135,6 +1136,10 @@ export function isJSDocOverrideTag(node: Node): node is JSDocOverrideTag {
return node.kind === SyntaxKind.JSDocOverrideTag;
}
export function isJSDocOverloadTag(node: Node): node is JSDocOverloadTag {
return node.kind === SyntaxKind.JSDocOverloadTag;
}
export function isJSDocDeprecatedTag(node: Node): node is JSDocDeprecatedTag {
return node.kind === SyntaxKind.JSDocDeprecatedTag;
}

View File

@ -177,6 +177,7 @@ import {
JSDocNonNullableType,
JSDocNullableType,
JSDocOptionalType,
JSDocOverloadTag,
JSDocOverrideTag,
JSDocParameterTag,
JSDocPrivateTag,
@ -8782,6 +8783,9 @@ namespace Parser {
case "callback":
tag = parseCallbackTag(start, tagName, margin, indentText);
break;
case "overload":
tag = parseOverloadTag(start, tagName, margin, indentText);
break;
case "see":
tag = parseSeeTag(start, tagName, margin, indentText);
break;
@ -9275,10 +9279,7 @@ namespace Parser {
return createNodeArray(parameters || [], pos);
}
function parseCallbackTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocCallbackTag {
const fullName = parseJSDocTypeNameWithNamespace();
skipWhitespace();
let comment = parseTagComments(indent);
function parseJSDocSignature(start: number, indent: number): JSDocSignature {
const parameters = parseCallbackTagParameters(indent);
const returnTag = tryParse(() => {
if (parseOptionalJsdoc(SyntaxKind.AtToken)) {
@ -9288,7 +9289,14 @@ namespace Parser {
}
}
});
const typeExpression = finishNode(factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), start);
return finishNode(factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), start);
}
function parseCallbackTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocCallbackTag {
const fullName = parseJSDocTypeNameWithNamespace();
skipWhitespace();
let comment = parseTagComments(indent);
const typeExpression = parseJSDocSignature(start, indent);
if (!comment) {
comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);
}
@ -9296,6 +9304,17 @@ namespace Parser {
return finishNode(factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), start, end);
}
function parseOverloadTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocOverloadTag {
skipWhitespace();
let comment = parseTagComments(indent);
const typeExpression = parseJSDocSignature(start, indent);
if (!comment) {
comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);
}
const end = comment !== undefined ? getNodePos() : typeExpression.end;
return finishNode(factory.createJSDocOverloadTag(tagName, typeExpression, comment), start, end);
}
function escapedTextsEqual(a: EntityName, b: EntityName): boolean {
while (!ts.isIdentifier(a) || !ts.isIdentifier(b)) {
if (!ts.isIdentifier(a) && !ts.isIdentifier(b) && a.right.escapedText === b.right.escapedText) {

View File

@ -423,6 +423,7 @@ export const enum SyntaxKind {
JSDocReadonlyTag,
JSDocOverrideTag,
JSDocCallbackTag,
JSDocOverloadTag,
JSDocEnumTag,
JSDocParameterTag,
JSDocReturnTag,
@ -4065,6 +4066,13 @@ export interface JSDocCallbackTag extends JSDocTag, NamedDeclaration, LocalsCont
readonly typeExpression: JSDocSignature;
}
export interface JSDocOverloadTag extends JSDocTag {
readonly kind: SyntaxKind.JSDocOverloadTag;
readonly parent: JSDoc;
readonly typeExpression: JSDocSignature;
}
export interface JSDocThrowsTag extends JSDocTag {
readonly kind: SyntaxKind.JSDocThrowsTag;
readonly typeExpression?: JSDocTypeExpression;
@ -8524,6 +8532,8 @@ export interface NodeFactory {
updateJSDocEnumTag(node: JSDocEnumTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray<JSDocComment> | undefined): JSDocEnumTag;
createJSDocCallbackTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray<JSDocComment>): JSDocCallbackTag;
updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocCallbackTag;
createJSDocOverloadTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, comment?: string | NodeArray<JSDocComment>): JSDocOverloadTag;
updateJSDocOverloadTag(node: JSDocOverloadTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, comment: string | NodeArray<JSDocComment> | undefined): JSDocOverloadTag;
createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocAugmentsTag;
updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | NodeArray<JSDocComment> | undefined): JSDocAugmentsTag;
createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocImplementsTag;

View File

@ -271,6 +271,7 @@ import {
isJSDocMemberName,
isJSDocNameReference,
isJSDocNode,
isJSDocOverloadTag,
isJSDocParameterTag,
isJSDocPropertyLikeTag,
isJSDocSignature,
@ -5801,7 +5802,7 @@ export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParam
/** template tags are only available when a typedef isn't already using them */
function isNonTypeAliasTemplate(tag: JSDocTag): tag is JSDocTemplateTag {
return isJSDocTemplateTag(tag) && !(tag.parent.kind === SyntaxKind.JSDoc && tag.parent.tags!.some(isJSDocTypeAlias));
return isJSDocTemplateTag(tag) && !(tag.parent.kind === SyntaxKind.JSDoc && (tag.parent.tags!.some(isJSDocTypeAlias) || tag.parent.tags!.some(isJSDocOverloadTag)));
}
/**

View File

@ -124,6 +124,7 @@ import {
isJSDocEnumTag,
isJSDocFunctionType,
isJSDocImplementsTag,
isJSDocOverloadTag,
isJSDocOverrideTag,
isJSDocParameterTag,
isJSDocPrivateTag,
@ -1210,6 +1211,14 @@ function formatJSDocLink(link: JSDocLink | JSDocLinkCode | JSDocLinkPlain) {
*/
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[] {
if (isJSDocSignature(node)) {
if (isJSDoc(node.parent)) {
const overloadTag = find(node.parent.tags, (tag) => {
return isJSDocOverloadTag(tag) && tag.typeExpression === node;
});
if (overloadTag) {
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined);
}
}
return emptyArray;
}
if (isJSDocTypeAlias(node)) {

View File

@ -4339,24 +4339,25 @@ declare namespace ts {
JSDocReadonlyTag = 339,
JSDocOverrideTag = 340,
JSDocCallbackTag = 341,
JSDocEnumTag = 342,
JSDocParameterTag = 343,
JSDocReturnTag = 344,
JSDocThisTag = 345,
JSDocTypeTag = 346,
JSDocTemplateTag = 347,
JSDocTypedefTag = 348,
JSDocSeeTag = 349,
JSDocPropertyTag = 350,
JSDocThrowsTag = 351,
SyntaxList = 352,
NotEmittedStatement = 353,
PartiallyEmittedExpression = 354,
CommaListExpression = 355,
MergeDeclarationMarker = 356,
EndOfDeclarationMarker = 357,
SyntheticReferenceExpression = 358,
Count = 359,
JSDocOverloadTag = 342,
JSDocEnumTag = 343,
JSDocParameterTag = 344,
JSDocReturnTag = 345,
JSDocThisTag = 346,
JSDocTypeTag = 347,
JSDocTemplateTag = 348,
JSDocTypedefTag = 349,
JSDocSeeTag = 350,
JSDocPropertyTag = 351,
JSDocThrowsTag = 352,
SyntaxList = 353,
NotEmittedStatement = 354,
PartiallyEmittedExpression = 355,
CommaListExpression = 356,
MergeDeclarationMarker = 357,
EndOfDeclarationMarker = 358,
SyntheticReferenceExpression = 359,
Count = 360,
FirstAssignment = 63,
LastAssignment = 78,
FirstCompoundAssignment = 64,
@ -4385,9 +4386,9 @@ declare namespace ts {
LastStatement = 256,
FirstNode = 163,
FirstJSDocNode = 312,
LastJSDocNode = 351,
LastJSDocNode = 352,
FirstJSDocTagNode = 330,
LastJSDocTagNode = 351
LastJSDocTagNode = 352
}
type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia;
type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral;
@ -5946,6 +5947,11 @@ declare namespace ts {
readonly name?: Identifier;
readonly typeExpression: JSDocSignature;
}
interface JSDocOverloadTag extends JSDocTag {
readonly kind: SyntaxKind.JSDocOverloadTag;
readonly parent: JSDoc;
readonly typeExpression: JSDocSignature;
}
interface JSDocThrowsTag extends JSDocTag {
readonly kind: SyntaxKind.JSDocThrowsTag;
readonly typeExpression?: JSDocTypeExpression;
@ -7800,6 +7806,8 @@ declare namespace ts {
updateJSDocEnumTag(node: JSDocEnumTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray<JSDocComment> | undefined): JSDocEnumTag;
createJSDocCallbackTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray<JSDocComment>): JSDocCallbackTag;
updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocCallbackTag;
createJSDocOverloadTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, comment?: string | NodeArray<JSDocComment>): JSDocOverloadTag;
updateJSDocOverloadTag(node: JSDocOverloadTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, comment: string | NodeArray<JSDocComment> | undefined): JSDocOverloadTag;
createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocAugmentsTag;
updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | NodeArray<JSDocComment> | undefined): JSDocAugmentsTag;
createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocImplementsTag;
@ -9056,6 +9064,7 @@ declare namespace ts {
function isJSDocProtectedTag(node: Node): node is JSDocProtectedTag;
function isJSDocReadonlyTag(node: Node): node is JSDocReadonlyTag;
function isJSDocOverrideTag(node: Node): node is JSDocOverrideTag;
function isJSDocOverloadTag(node: Node): node is JSDocOverloadTag;
function isJSDocDeprecatedTag(node: Node): node is JSDocDeprecatedTag;
function isJSDocSeeTag(node: Node): node is JSDocSeeTag;
function isJSDocEnumTag(node: Node): node is JSDocEnumTag;

View File

@ -404,24 +404,25 @@ declare namespace ts {
JSDocReadonlyTag = 339,
JSDocOverrideTag = 340,
JSDocCallbackTag = 341,
JSDocEnumTag = 342,
JSDocParameterTag = 343,
JSDocReturnTag = 344,
JSDocThisTag = 345,
JSDocTypeTag = 346,
JSDocTemplateTag = 347,
JSDocTypedefTag = 348,
JSDocSeeTag = 349,
JSDocPropertyTag = 350,
JSDocThrowsTag = 351,
SyntaxList = 352,
NotEmittedStatement = 353,
PartiallyEmittedExpression = 354,
CommaListExpression = 355,
MergeDeclarationMarker = 356,
EndOfDeclarationMarker = 357,
SyntheticReferenceExpression = 358,
Count = 359,
JSDocOverloadTag = 342,
JSDocEnumTag = 343,
JSDocParameterTag = 344,
JSDocReturnTag = 345,
JSDocThisTag = 346,
JSDocTypeTag = 347,
JSDocTemplateTag = 348,
JSDocTypedefTag = 349,
JSDocSeeTag = 350,
JSDocPropertyTag = 351,
JSDocThrowsTag = 352,
SyntaxList = 353,
NotEmittedStatement = 354,
PartiallyEmittedExpression = 355,
CommaListExpression = 356,
MergeDeclarationMarker = 357,
EndOfDeclarationMarker = 358,
SyntheticReferenceExpression = 359,
Count = 360,
FirstAssignment = 63,
LastAssignment = 78,
FirstCompoundAssignment = 64,
@ -450,9 +451,9 @@ declare namespace ts {
LastStatement = 256,
FirstNode = 163,
FirstJSDocNode = 312,
LastJSDocNode = 351,
LastJSDocNode = 352,
FirstJSDocTagNode = 330,
LastJSDocTagNode = 351
LastJSDocTagNode = 352
}
type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia;
type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral;
@ -2011,6 +2012,11 @@ declare namespace ts {
readonly name?: Identifier;
readonly typeExpression: JSDocSignature;
}
interface JSDocOverloadTag extends JSDocTag {
readonly kind: SyntaxKind.JSDocOverloadTag;
readonly parent: JSDoc;
readonly typeExpression: JSDocSignature;
}
interface JSDocThrowsTag extends JSDocTag {
readonly kind: SyntaxKind.JSDocThrowsTag;
readonly typeExpression?: JSDocTypeExpression;
@ -3865,6 +3871,8 @@ declare namespace ts {
updateJSDocEnumTag(node: JSDocEnumTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray<JSDocComment> | undefined): JSDocEnumTag;
createJSDocCallbackTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray<JSDocComment>): JSDocCallbackTag;
updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocCallbackTag;
createJSDocOverloadTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, comment?: string | NodeArray<JSDocComment>): JSDocOverloadTag;
updateJSDocOverloadTag(node: JSDocOverloadTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, comment: string | NodeArray<JSDocComment> | undefined): JSDocOverloadTag;
createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocAugmentsTag;
updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | NodeArray<JSDocComment> | undefined): JSDocAugmentsTag;
createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocImplementsTag;
@ -5121,6 +5129,7 @@ declare namespace ts {
function isJSDocProtectedTag(node: Node): node is JSDocProtectedTag;
function isJSDocReadonlyTag(node: Node): node is JSDocReadonlyTag;
function isJSDocOverrideTag(node: Node): node is JSDocOverrideTag;
function isJSDocOverloadTag(node: Node): node is JSDocOverloadTag;
function isJSDocDeprecatedTag(node: Node): node is JSDocDeprecatedTag;
function isJSDocSeeTag(node: Node): node is JSDocSeeTag;
function isJSDocEnumTag(node: Node): node is JSDocEnumTag;

View File

@ -0,0 +1,95 @@
// === /tests/cases/fourslash/foo.js ===
// /**
// * @overload
// * @param {number} x
// * @returns {number}
// *
// * @overload
// * @param {string} x
// * @returns {string}
// *
// * @param {unknown} [|x|]
// * @returns {unknown}
// */
// function foo([|x|]/*FIND ALL REFS*/) {
// return [|x|];
// }
[
{
"definition": {
"containerKind": "",
"containerName": "",
"fileName": "/tests/cases/fourslash/foo.js",
"kind": "parameter",
"name": "(parameter) x: unknown",
"textSpan": {
"start": 183,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "parameter",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "x",
"kind": "parameterName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "unknown",
"kind": "keyword"
}
]
},
"references": [
{
"textSpan": {
"start": 141,
"length": 1
},
"fileName": "/tests/cases/fourslash/foo.js",
"isWriteAccess": false,
"isDefinition": false
},
{
"textSpan": {
"start": 183,
"length": 1
},
"fileName": "/tests/cases/fourslash/foo.js",
"isWriteAccess": true,
"isDefinition": true
},
{
"textSpan": {
"start": 197,
"length": 1
},
"fileName": "/tests/cases/fourslash/foo.js",
"isWriteAccess": false,
"isDefinition": false
}
]
}
]

View File

@ -0,0 +1,121 @@
//// [jsFileAlternativeUseOfOverloadTag.js]
// These are a few examples of existing alternative uses of @overload tag.
// They will not work as expected with our implementation, but we are
// trying to make sure that our changes do not result in any crashes here.
const example1 = {
/**
* @overload Example1(value)
* Creates Example1
* @param value [String]
*/
constructor: function Example1(value, options) {},
};
const example2 = {
/**
* Example 2
*
* @overload Example2(value)
* Creates Example2
* @param value [String]
* @param secretAccessKey [String]
* @param sessionToken [String]
* @example Creates with string value
* const example = new Example('');
* @overload Example2(options)
* Creates Example2
* @option options value [String]
* @example Creates with options object
* const example = new Example2({
* value: '',
* });
*/
constructor: function Example2() {},
};
const example3 = {
/**
* @overload evaluate(options = {}, [callback])
* Evaluate something
* @note Something interesting
* @param options [map]
* @return [string] returns evaluation result
* @return [null] returns nothing if callback provided
* @callback callback function (error, result)
* If callback is provided it will be called with evaluation result
* @param error [Error]
* @param result [String]
* @see callback
*/
evaluate: function evaluate(options, callback) {},
};
//// [jsFileAlternativeUseOfOverloadTag.js]
// These are a few examples of existing alternative uses of @overload tag.
// They will not work as expected with our implementation, but we are
// trying to make sure that our changes do not result in any crashes here.
var example1 = {
/**
* @overload Example1(value)
* Creates Example1
* @param value [String]
*/
constructor: function Example1(value, options) { },
};
var example2 = {
/**
* Example 2
*
* @overload Example2(value)
* Creates Example2
* @param value [String]
* @param secretAccessKey [String]
* @param sessionToken [String]
* @example Creates with string value
* const example = new Example('');
* @overload Example2(options)
* Creates Example2
* @option options value [String]
* @example Creates with options object
* const example = new Example2({
* value: '',
* });
*/
constructor: function Example2() { },
};
var example3 = {
/**
* @overload evaluate(options = {}, [callback])
* Evaluate something
* @note Something interesting
* @param options [map]
* @return [string] returns evaluation result
* @return [null] returns nothing if callback provided
* @callback callback function (error, result)
* If callback is provided it will be called with evaluation result
* @param error [Error]
* @param result [String]
* @see callback
*/
evaluate: function evaluate(options, callback) { },
};
//// [jsFileAlternativeUseOfOverloadTag.d.ts]
declare namespace example1 {
function constructor(value: any, options: any): void;
}
declare namespace example2 {
export function constructor_1(): void;
export { constructor_1 as constructor };
}
declare namespace example3 {
function evaluate(options: any, callback: any): void;
}
/**
* function (error, result)
* If callback is provided it will be called with evaluation result
*/
type callback = (error: any, result: any) => any;

View File

@ -0,0 +1,72 @@
=== tests/cases/compiler/jsFileAlternativeUseOfOverloadTag.js ===
// These are a few examples of existing alternative uses of @overload tag.
// They will not work as expected with our implementation, but we are
// trying to make sure that our changes do not result in any crashes here.
const example1 = {
>example1 : Symbol(example1, Decl(jsFileAlternativeUseOfOverloadTag.js, 4, 5))
/**
* @overload Example1(value)
* Creates Example1
* @param value [String]
*/
constructor: function Example1(value, options) {},
>constructor : Symbol(constructor, Decl(jsFileAlternativeUseOfOverloadTag.js, 4, 18))
>Example1 : Symbol(Example1, Decl(jsFileAlternativeUseOfOverloadTag.js, 10, 14))
>value : Symbol(value, Decl(jsFileAlternativeUseOfOverloadTag.js, 10, 33))
>options : Symbol(options, Decl(jsFileAlternativeUseOfOverloadTag.js, 10, 39))
};
const example2 = {
>example2 : Symbol(example2, Decl(jsFileAlternativeUseOfOverloadTag.js, 13, 5))
/**
* Example 2
*
* @overload Example2(value)
* Creates Example2
* @param value [String]
* @param secretAccessKey [String]
* @param sessionToken [String]
* @example Creates with string value
* const example = new Example('');
* @overload Example2(options)
* Creates Example2
* @option options value [String]
* @example Creates with options object
* const example = new Example2({
* value: '',
* });
*/
constructor: function Example2() {},
>constructor : Symbol(constructor, Decl(jsFileAlternativeUseOfOverloadTag.js, 13, 18))
>Example2 : Symbol(Example2, Decl(jsFileAlternativeUseOfOverloadTag.js, 32, 14))
};
const example3 = {
>example3 : Symbol(example3, Decl(jsFileAlternativeUseOfOverloadTag.js, 35, 5))
/**
* @overload evaluate(options = {}, [callback])
* Evaluate something
* @note Something interesting
* @param options [map]
* @return [string] returns evaluation result
* @return [null] returns nothing if callback provided
* @callback callback function (error, result)
* If callback is provided it will be called with evaluation result
* @param error [Error]
* @param result [String]
* @see callback
*/
evaluate: function evaluate(options, callback) {},
>evaluate : Symbol(evaluate, Decl(jsFileAlternativeUseOfOverloadTag.js, 35, 18))
>evaluate : Symbol(evaluate, Decl(jsFileAlternativeUseOfOverloadTag.js, 49, 11))
>options : Symbol(options, Decl(jsFileAlternativeUseOfOverloadTag.js, 49, 30))
>callback : Symbol(callback, Decl(jsFileAlternativeUseOfOverloadTag.js, 49, 38))
};

View File

@ -0,0 +1,78 @@
=== tests/cases/compiler/jsFileAlternativeUseOfOverloadTag.js ===
// These are a few examples of existing alternative uses of @overload tag.
// They will not work as expected with our implementation, but we are
// trying to make sure that our changes do not result in any crashes here.
const example1 = {
>example1 : { constructor: (value: any, options: any) => void; }
>{ /** * @overload Example1(value) * Creates Example1 * @param value [String] */ constructor: function Example1(value, options) {},} : { constructor: (value: any, options: any) => void; }
/**
* @overload Example1(value)
* Creates Example1
* @param value [String]
*/
constructor: function Example1(value, options) {},
>constructor : (value: any, options: any) => void
>function Example1(value, options) {} : (value: any, options: any) => void
>Example1 : (value: any, options: any) => void
>value : any
>options : any
};
const example2 = {
>example2 : { constructor: () => void; }
>{ /** * Example 2 * * @overload Example2(value) * Creates Example2 * @param value [String] * @param secretAccessKey [String] * @param sessionToken [String] * @example Creates with string value * const example = new Example(''); * @overload Example2(options) * Creates Example2 * @option options value [String] * @example Creates with options object * const example = new Example2({ * value: '', * }); */ constructor: function Example2() {},} : { constructor: () => void; }
/**
* Example 2
*
* @overload Example2(value)
* Creates Example2
* @param value [String]
* @param secretAccessKey [String]
* @param sessionToken [String]
* @example Creates with string value
* const example = new Example('');
* @overload Example2(options)
* Creates Example2
* @option options value [String]
* @example Creates with options object
* const example = new Example2({
* value: '',
* });
*/
constructor: function Example2() {},
>constructor : () => void
>function Example2() {} : () => void
>Example2 : () => void
};
const example3 = {
>example3 : { evaluate: (options: any, callback: any) => void; }
>{ /** * @overload evaluate(options = {}, [callback]) * Evaluate something * @note Something interesting * @param options [map] * @return [string] returns evaluation result * @return [null] returns nothing if callback provided * @callback callback function (error, result) * If callback is provided it will be called with evaluation result * @param error [Error] * @param result [String] * @see callback */ evaluate: function evaluate(options, callback) {},} : { evaluate: (options: any, callback: any) => void; }
/**
* @overload evaluate(options = {}, [callback])
* Evaluate something
* @note Something interesting
* @param options [map]
* @return [string] returns evaluation result
* @return [null] returns nothing if callback provided
* @callback callback function (error, result)
* If callback is provided it will be called with evaluation result
* @param error [Error]
* @param result [String]
* @see callback
*/
evaluate: function evaluate(options, callback) {},
>evaluate : (options: any, callback: any) => void
>function evaluate(options, callback) {} : (options: any, callback: any) => void
>evaluate : (options: any, callback: any) => void
>options : any
>callback : any
};

View File

@ -0,0 +1,131 @@
//// [jsFileFunctionOverloads.js]
/**
* @overload
* @param {number} x
* @returns {'number'}
*/
/**
* @overload
* @param {string} x
* @returns {'string'}
*/
/**
* @overload
* @param {boolean} x
* @returns {'boolean'}
*/
/**
* @param {unknown} x
* @returns {string}
*/
function getTypeName(x) {
return typeof x;
}
/**
* @template T
* @param {T} x
* @returns {T}
*/
const identity = x => x;
/**
* @template T
* @template U
* @overload
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*/
/**
* @template T
* @overload
* @param {T[][]} array
* @returns {T[]}
*/
/**
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable = identity) {
/** @type {unknown[]} */
const result = [];
for (let i = 0; i < array.length; i += 1) {
result.push(.../** @type {unknown[]} */(iterable(array[i])));
}
return result;
}
//// [jsFileFunctionOverloads.js]
/**
* @overload
* @param {number} x
* @returns {'number'}
*/
/**
* @overload
* @param {string} x
* @returns {'string'}
*/
/**
* @overload
* @param {boolean} x
* @returns {'boolean'}
*/
/**
* @param {unknown} x
* @returns {string}
*/
function getTypeName(x) {
return typeof x;
}
/**
* @template T
* @param {T} x
* @returns {T}
*/
var identity = function (x) { return x; };
/**
* @template T
* @template U
* @overload
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*/
/**
* @template T
* @overload
* @param {T[][]} array
* @returns {T[]}
*/
/**
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable) {
if (iterable === void 0) { iterable = identity; }
/** @type {unknown[]} */
var result = [];
for (var i = 0; i < array.length; i += 1) {
result.push.apply(result, /** @type {unknown[]} */ (iterable(array[i])));
}
return result;
}
//// [jsFileFunctionOverloads.d.ts]
declare function getTypeName(x: number): 'number';
declare function getTypeName(x: string): 'string';
declare function getTypeName(x: boolean): 'boolean';
declare function flatMap<T, U>(array: T[], iterable: (x: T) => U[]): U[];
declare function flatMap<T>(array: T[][]): T[];
/**
* @template T
* @param {T} x
* @returns {T}
*/
declare function identity<T>(x: T): T;

View File

@ -0,0 +1,87 @@
=== tests/cases/compiler/jsFileFunctionOverloads.js ===
/**
* @overload
* @param {number} x
* @returns {'number'}
*/
/**
* @overload
* @param {string} x
* @returns {'string'}
*/
/**
* @overload
* @param {boolean} x
* @returns {'boolean'}
*/
/**
* @param {unknown} x
* @returns {string}
*/
function getTypeName(x) {
>getTypeName : Symbol(getTypeName, Decl(jsFileFunctionOverloads.js, 0, 0))
>x : Symbol(x, Decl(jsFileFunctionOverloads.js, 19, 22))
return typeof x;
>x : Symbol(x, Decl(jsFileFunctionOverloads.js, 19, 22))
}
/**
* @template T
* @param {T} x
* @returns {T}
*/
const identity = x => x;
>identity : Symbol(identity, Decl(jsFileFunctionOverloads.js, 28, 5))
>x : Symbol(x, Decl(jsFileFunctionOverloads.js, 28, 16))
>x : Symbol(x, Decl(jsFileFunctionOverloads.js, 28, 16))
/**
* @template T
* @template U
* @overload
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*/
/**
* @template T
* @overload
* @param {T[][]} array
* @returns {T[]}
*/
/**
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable = identity) {
>flatMap : Symbol(flatMap, Decl(jsFileFunctionOverloads.js, 28, 24))
>array : Symbol(array, Decl(jsFileFunctionOverloads.js, 49, 17))
>iterable : Symbol(iterable, Decl(jsFileFunctionOverloads.js, 49, 23))
>identity : Symbol(identity, Decl(jsFileFunctionOverloads.js, 28, 5))
/** @type {unknown[]} */
const result = [];
>result : Symbol(result, Decl(jsFileFunctionOverloads.js, 51, 7))
for (let i = 0; i < array.length; i += 1) {
>i : Symbol(i, Decl(jsFileFunctionOverloads.js, 52, 10))
>i : Symbol(i, Decl(jsFileFunctionOverloads.js, 52, 10))
>array.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>array : Symbol(array, Decl(jsFileFunctionOverloads.js, 49, 17))
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>i : Symbol(i, Decl(jsFileFunctionOverloads.js, 52, 10))
result.push(.../** @type {unknown[]} */(iterable(array[i])));
>result.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
>result : Symbol(result, Decl(jsFileFunctionOverloads.js, 51, 7))
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
>iterable : Symbol(iterable, Decl(jsFileFunctionOverloads.js, 49, 23))
>array : Symbol(array, Decl(jsFileFunctionOverloads.js, 49, 17))
>i : Symbol(i, Decl(jsFileFunctionOverloads.js, 52, 10))
}
return result;
>result : Symbol(result, Decl(jsFileFunctionOverloads.js, 51, 7))
}

View File

@ -0,0 +1,99 @@
=== tests/cases/compiler/jsFileFunctionOverloads.js ===
/**
* @overload
* @param {number} x
* @returns {'number'}
*/
/**
* @overload
* @param {string} x
* @returns {'string'}
*/
/**
* @overload
* @param {boolean} x
* @returns {'boolean'}
*/
/**
* @param {unknown} x
* @returns {string}
*/
function getTypeName(x) {
>getTypeName : { (x: number): 'number'; (x: string): 'string'; (x: boolean): 'boolean'; }
>x : unknown
return typeof x;
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : unknown
}
/**
* @template T
* @param {T} x
* @returns {T}
*/
const identity = x => x;
>identity : <T>(x: T) => T
>x => x : <T>(x: T) => T
>x : T
>x : T
/**
* @template T
* @template U
* @overload
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*/
/**
* @template T
* @overload
* @param {T[][]} array
* @returns {T[]}
*/
/**
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable = identity) {
>flatMap : { <T, U>(array: T[], iterable: (x: T) => U[]): U[]; <T>(array: T[][]): T[]; }
>array : unknown[]
>iterable : (x: unknown) => unknown
>identity : <T>(x: T) => T
/** @type {unknown[]} */
const result = [];
>result : unknown[]
>[] : undefined[]
for (let i = 0; i < array.length; i += 1) {
>i : number
>0 : 0
>i < array.length : boolean
>i : number
>array.length : number
>array : unknown[]
>length : number
>i += 1 : number
>i : number
>1 : 1
result.push(.../** @type {unknown[]} */(iterable(array[i])));
>result.push(.../** @type {unknown[]} */(iterable(array[i]))) : number
>result.push : (...items: unknown[]) => number
>result : unknown[]
>push : (...items: unknown[]) => number
>.../** @type {unknown[]} */(iterable(array[i])) : unknown
>(iterable(array[i])) : unknown[]
>iterable(array[i]) : unknown
>iterable : (x: unknown) => unknown
>array[i] : unknown
>array : unknown[]
>i : number
}
return result;
>result : unknown[]
}

View File

@ -0,0 +1,121 @@
//// [jsFileFunctionOverloads2.js]
// Also works if all @overload tags are combined in one comment.
/**
* @overload
* @param {number} x
* @returns {'number'}
*
* @overload
* @param {string} x
* @returns {'string'}
*
* @overload
* @param {boolean} x
* @returns {'boolean'}
*
* @param {unknown} x
* @returns {string}
*/
function getTypeName(x) {
return typeof x;
}
/**
* @template T
* @param {T} x
* @returns {T}
*/
const identity = x => x;
/**
* @template T
* @template U
* @overload
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*
* @overload
* @param {T[][]} array
* @returns {T[]}
*
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable = identity) {
/** @type {unknown[]} */
const result = [];
for (let i = 0; i < array.length; i += 1) {
result.push(.../** @type {unknown[]} */(iterable(array[i])));
}
return result;
}
//// [jsFileFunctionOverloads2.js]
// Also works if all @overload tags are combined in one comment.
/**
* @overload
* @param {number} x
* @returns {'number'}
*
* @overload
* @param {string} x
* @returns {'string'}
*
* @overload
* @param {boolean} x
* @returns {'boolean'}
*
* @param {unknown} x
* @returns {string}
*/
function getTypeName(x) {
return typeof x;
}
/**
* @template T
* @param {T} x
* @returns {T}
*/
var identity = function (x) { return x; };
/**
* @template T
* @template U
* @overload
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*
* @overload
* @param {T[][]} array
* @returns {T[]}
*
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable) {
if (iterable === void 0) { iterable = identity; }
/** @type {unknown[]} */
var result = [];
for (var i = 0; i < array.length; i += 1) {
result.push.apply(result, /** @type {unknown[]} */ (iterable(array[i])));
}
return result;
}
//// [jsFileFunctionOverloads2.d.ts]
declare function getTypeName(x: number): 'number';
declare function getTypeName(x: string): 'string';
declare function getTypeName(x: boolean): 'boolean';
declare function flatMap<T, U>(array: T[], iterable: (x: T) => U[]): U[];
declare function flatMap<T, U>(array: T[][]): T[];
/**
* @template T
* @param {T} x
* @returns {T}
*/
declare function identity<T>(x: T): T;

View File

@ -0,0 +1,82 @@
=== tests/cases/compiler/jsFileFunctionOverloads2.js ===
// Also works if all @overload tags are combined in one comment.
/**
* @overload
* @param {number} x
* @returns {'number'}
*
* @overload
* @param {string} x
* @returns {'string'}
*
* @overload
* @param {boolean} x
* @returns {'boolean'}
*
* @param {unknown} x
* @returns {string}
*/
function getTypeName(x) {
>getTypeName : Symbol(getTypeName, Decl(jsFileFunctionOverloads2.js, 0, 0))
>x : Symbol(x, Decl(jsFileFunctionOverloads2.js, 17, 22))
return typeof x;
>x : Symbol(x, Decl(jsFileFunctionOverloads2.js, 17, 22))
}
/**
* @template T
* @param {T} x
* @returns {T}
*/
const identity = x => x;
>identity : Symbol(identity, Decl(jsFileFunctionOverloads2.js, 26, 5))
>x : Symbol(x, Decl(jsFileFunctionOverloads2.js, 26, 16))
>x : Symbol(x, Decl(jsFileFunctionOverloads2.js, 26, 16))
/**
* @template T
* @template U
* @overload
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*
* @overload
* @param {T[][]} array
* @returns {T[]}
*
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable = identity) {
>flatMap : Symbol(flatMap, Decl(jsFileFunctionOverloads2.js, 26, 24))
>array : Symbol(array, Decl(jsFileFunctionOverloads2.js, 44, 17))
>iterable : Symbol(iterable, Decl(jsFileFunctionOverloads2.js, 44, 23))
>identity : Symbol(identity, Decl(jsFileFunctionOverloads2.js, 26, 5))
/** @type {unknown[]} */
const result = [];
>result : Symbol(result, Decl(jsFileFunctionOverloads2.js, 46, 7))
for (let i = 0; i < array.length; i += 1) {
>i : Symbol(i, Decl(jsFileFunctionOverloads2.js, 47, 10))
>i : Symbol(i, Decl(jsFileFunctionOverloads2.js, 47, 10))
>array.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>array : Symbol(array, Decl(jsFileFunctionOverloads2.js, 44, 17))
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>i : Symbol(i, Decl(jsFileFunctionOverloads2.js, 47, 10))
result.push(.../** @type {unknown[]} */(iterable(array[i])));
>result.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
>result : Symbol(result, Decl(jsFileFunctionOverloads2.js, 46, 7))
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
>iterable : Symbol(iterable, Decl(jsFileFunctionOverloads2.js, 44, 23))
>array : Symbol(array, Decl(jsFileFunctionOverloads2.js, 44, 17))
>i : Symbol(i, Decl(jsFileFunctionOverloads2.js, 47, 10))
}
return result;
>result : Symbol(result, Decl(jsFileFunctionOverloads2.js, 46, 7))
}

View File

@ -0,0 +1,94 @@
=== tests/cases/compiler/jsFileFunctionOverloads2.js ===
// Also works if all @overload tags are combined in one comment.
/**
* @overload
* @param {number} x
* @returns {'number'}
*
* @overload
* @param {string} x
* @returns {'string'}
*
* @overload
* @param {boolean} x
* @returns {'boolean'}
*
* @param {unknown} x
* @returns {string}
*/
function getTypeName(x) {
>getTypeName : { (x: number): 'number'; (x: string): 'string'; (x: boolean): 'boolean'; }
>x : unknown
return typeof x;
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : unknown
}
/**
* @template T
* @param {T} x
* @returns {T}
*/
const identity = x => x;
>identity : <T>(x: T) => T
>x => x : <T>(x: T) => T
>x : T
>x : T
/**
* @template T
* @template U
* @overload
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*
* @overload
* @param {T[][]} array
* @returns {T[]}
*
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable = identity) {
>flatMap : { <T, U>(array: T[], iterable: (x: T) => U[]): U[]; <T, U>(array: T[][]): T[]; }
>array : unknown[]
>iterable : (x: unknown) => unknown
>identity : <T>(x: T) => T
/** @type {unknown[]} */
const result = [];
>result : unknown[]
>[] : undefined[]
for (let i = 0; i < array.length; i += 1) {
>i : number
>0 : 0
>i < array.length : boolean
>i : number
>array.length : number
>array : unknown[]
>length : number
>i += 1 : number
>i : number
>1 : 1
result.push(.../** @type {unknown[]} */(iterable(array[i])));
>result.push(.../** @type {unknown[]} */(iterable(array[i]))) : number
>result.push : (...items: unknown[]) => number
>result : unknown[]
>push : (...items: unknown[]) => number
>.../** @type {unknown[]} */(iterable(array[i])) : unknown
>(iterable(array[i])) : unknown[]
>iterable(array[i]) : unknown
>iterable : (x: unknown) => unknown
>array[i] : unknown
>array : unknown[]
>i : number
}
return result;
>result : unknown[]
}

View File

@ -0,0 +1,112 @@
//// [jsFileMethodOverloads.js]
/**
* @template T
*/
class Example {
/**
* @param {T} value
*/
constructor(value) {
this.value = value;
}
/**
* @overload
* @param {Example<number>} this
* @returns {'number'}
*/
/**
* @overload
* @param {Example<string>} this
* @returns {'string'}
*/
/**
* @returns {string}
*/
getTypeName() {
return typeof this.value;
}
/**
* @template U
* @overload
* @param {(y: T) => U} fn
* @returns {U}
*/
/**
* @overload
* @returns {T}
*/
/**
* @param {(y: T) => unknown} [fn]
* @returns {unknown}
*/
transform(fn) {
return fn ? fn(this.value) : this.value;
}
}
//// [jsFileMethodOverloads.js]
/**
* @template T
*/
var Example = /** @class */ (function () {
/**
* @param {T} value
*/
function Example(value) {
this.value = value;
}
/**
* @overload
* @param {Example<number>} this
* @returns {'number'}
*/
/**
* @overload
* @param {Example<string>} this
* @returns {'string'}
*/
/**
* @returns {string}
*/
Example.prototype.getTypeName = function () {
return typeof this.value;
};
/**
* @template U
* @overload
* @param {(y: T) => U} fn
* @returns {U}
*/
/**
* @overload
* @returns {T}
*/
/**
* @param {(y: T) => unknown} [fn]
* @returns {unknown}
*/
Example.prototype.transform = function (fn) {
return fn ? fn(this.value) : this.value;
};
return Example;
}());
//// [jsFileMethodOverloads.d.ts]
/**
* @template T
*/
declare class Example<T> {
/**
* @param {T} value
*/
constructor(value: T);
value: T;
getTypeName(this: Example<number>): 'number';
getTypeName(this: Example<string>): 'string';
transform<U>(fn: (y: T) => U): U;
transform(): T;
}

View File

@ -0,0 +1,72 @@
=== tests/cases/compiler/jsFileMethodOverloads.js ===
/**
* @template T
*/
class Example {
>Example : Symbol(Example, Decl(jsFileMethodOverloads.js, 0, 0))
/**
* @param {T} value
*/
constructor(value) {
>value : Symbol(value, Decl(jsFileMethodOverloads.js, 7, 14))
this.value = value;
>this.value : Symbol(Example.value, Decl(jsFileMethodOverloads.js, 7, 22))
>this : Symbol(Example, Decl(jsFileMethodOverloads.js, 0, 0))
>value : Symbol(Example.value, Decl(jsFileMethodOverloads.js, 7, 22))
>value : Symbol(value, Decl(jsFileMethodOverloads.js, 7, 14))
}
/**
* @overload
* @param {Example<number>} this
* @returns {'number'}
*/
/**
* @overload
* @param {Example<string>} this
* @returns {'string'}
*/
/**
* @returns {string}
*/
getTypeName() {
>getTypeName : Symbol(Example.getTypeName, Decl(jsFileMethodOverloads.js, 9, 3))
return typeof this.value;
>this.value : Symbol(Example.value, Decl(jsFileMethodOverloads.js, 7, 22))
>this : Symbol(Example, Decl(jsFileMethodOverloads.js, 0, 0))
>value : Symbol(Example.value, Decl(jsFileMethodOverloads.js, 7, 22))
}
/**
* @template U
* @overload
* @param {(y: T) => U} fn
* @returns {U}
*/
/**
* @overload
* @returns {T}
*/
/**
* @param {(y: T) => unknown} [fn]
* @returns {unknown}
*/
transform(fn) {
>transform : Symbol(Example.transform, Decl(jsFileMethodOverloads.js, 26, 3))
>fn : Symbol(fn, Decl(jsFileMethodOverloads.js, 42, 12))
return fn ? fn(this.value) : this.value;
>fn : Symbol(fn, Decl(jsFileMethodOverloads.js, 42, 12))
>fn : Symbol(fn, Decl(jsFileMethodOverloads.js, 42, 12))
>this.value : Symbol(Example.value, Decl(jsFileMethodOverloads.js, 7, 22))
>this : Symbol(Example, Decl(jsFileMethodOverloads.js, 0, 0))
>value : Symbol(Example.value, Decl(jsFileMethodOverloads.js, 7, 22))
>this.value : Symbol(Example.value, Decl(jsFileMethodOverloads.js, 7, 22))
>this : Symbol(Example, Decl(jsFileMethodOverloads.js, 0, 0))
>value : Symbol(Example.value, Decl(jsFileMethodOverloads.js, 7, 22))
}
}

View File

@ -0,0 +1,76 @@
=== tests/cases/compiler/jsFileMethodOverloads.js ===
/**
* @template T
*/
class Example {
>Example : Example<T>
/**
* @param {T} value
*/
constructor(value) {
>value : T
this.value = value;
>this.value = value : T
>this.value : any
>this : this
>value : any
>value : T
}
/**
* @overload
* @param {Example<number>} this
* @returns {'number'}
*/
/**
* @overload
* @param {Example<string>} this
* @returns {'string'}
*/
/**
* @returns {string}
*/
getTypeName() {
>getTypeName : { (this: Example<number>): 'number'; (this: Example<string>): 'string'; }
return typeof this.value;
>typeof this.value : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
>this.value : T
>this : this
>value : T
}
/**
* @template U
* @overload
* @param {(y: T) => U} fn
* @returns {U}
*/
/**
* @overload
* @returns {T}
*/
/**
* @param {(y: T) => unknown} [fn]
* @returns {unknown}
*/
transform(fn) {
>transform : { <U>(fn: (y: T) => U): U; (): T; }
>fn : (y: T) => unknown
return fn ? fn(this.value) : this.value;
>fn ? fn(this.value) : this.value : unknown
>fn : (y: T) => unknown
>fn(this.value) : unknown
>fn : (y: T) => unknown
>this.value : T
>this : this
>value : T
>this.value : T
>this : this
>value : T
}
}

View File

@ -0,0 +1,106 @@
//// [jsFileMethodOverloads2.js]
// Also works if all @overload tags are combined in one comment.
/**
* @template T
*/
class Example {
/**
* @param {T} value
*/
constructor(value) {
this.value = value;
}
/**
* @overload
* @param {Example<number>} this
* @returns {'number'}
*
* @overload
* @param {Example<string>} this
* @returns {'string'}
*
* @returns {string}
*/
getTypeName() {
return typeof this.value;
}
/**
* @template U
* @overload
* @param {(y: T) => U} fn
* @returns {U}
*
* @overload
* @returns {T}
*
* @param {(y: T) => unknown} [fn]
* @returns {unknown}
*/
transform(fn) {
return fn ? fn(this.value) : this.value;
}
}
//// [jsFileMethodOverloads2.js]
// Also works if all @overload tags are combined in one comment.
/**
* @template T
*/
var Example = /** @class */ (function () {
/**
* @param {T} value
*/
function Example(value) {
this.value = value;
}
/**
* @overload
* @param {Example<number>} this
* @returns {'number'}
*
* @overload
* @param {Example<string>} this
* @returns {'string'}
*
* @returns {string}
*/
Example.prototype.getTypeName = function () {
return typeof this.value;
};
/**
* @template U
* @overload
* @param {(y: T) => U} fn
* @returns {U}
*
* @overload
* @returns {T}
*
* @param {(y: T) => unknown} [fn]
* @returns {unknown}
*/
Example.prototype.transform = function (fn) {
return fn ? fn(this.value) : this.value;
};
return Example;
}());
//// [jsFileMethodOverloads2.d.ts]
/**
* @template T
*/
declare class Example<T> {
/**
* @param {T} value
*/
constructor(value: T);
value: T;
getTypeName(this: Example<number>): 'number';
getTypeName(this: Example<string>): 'string';
transform<U>(fn: (y: T) => U): U;
transform<U_1>(): T;
}

View File

@ -0,0 +1,69 @@
=== tests/cases/compiler/jsFileMethodOverloads2.js ===
// Also works if all @overload tags are combined in one comment.
/**
* @template T
*/
class Example {
>Example : Symbol(Example, Decl(jsFileMethodOverloads2.js, 0, 0))
/**
* @param {T} value
*/
constructor(value) {
>value : Symbol(value, Decl(jsFileMethodOverloads2.js, 8, 14))
this.value = value;
>this.value : Symbol(Example.value, Decl(jsFileMethodOverloads2.js, 8, 22))
>this : Symbol(Example, Decl(jsFileMethodOverloads2.js, 0, 0))
>value : Symbol(Example.value, Decl(jsFileMethodOverloads2.js, 8, 22))
>value : Symbol(value, Decl(jsFileMethodOverloads2.js, 8, 14))
}
/**
* @overload
* @param {Example<number>} this
* @returns {'number'}
*
* @overload
* @param {Example<string>} this
* @returns {'string'}
*
* @returns {string}
*/
getTypeName() {
>getTypeName : Symbol(Example.getTypeName, Decl(jsFileMethodOverloads2.js, 10, 3))
return typeof this.value;
>this.value : Symbol(Example.value, Decl(jsFileMethodOverloads2.js, 8, 22))
>this : Symbol(Example, Decl(jsFileMethodOverloads2.js, 0, 0))
>value : Symbol(Example.value, Decl(jsFileMethodOverloads2.js, 8, 22))
}
/**
* @template U
* @overload
* @param {(y: T) => U} fn
* @returns {U}
*
* @overload
* @returns {T}
*
* @param {(y: T) => unknown} [fn]
* @returns {unknown}
*/
transform(fn) {
>transform : Symbol(Example.transform, Decl(jsFileMethodOverloads2.js, 25, 3))
>fn : Symbol(fn, Decl(jsFileMethodOverloads2.js, 39, 12))
return fn ? fn(this.value) : this.value;
>fn : Symbol(fn, Decl(jsFileMethodOverloads2.js, 39, 12))
>fn : Symbol(fn, Decl(jsFileMethodOverloads2.js, 39, 12))
>this.value : Symbol(Example.value, Decl(jsFileMethodOverloads2.js, 8, 22))
>this : Symbol(Example, Decl(jsFileMethodOverloads2.js, 0, 0))
>value : Symbol(Example.value, Decl(jsFileMethodOverloads2.js, 8, 22))
>this.value : Symbol(Example.value, Decl(jsFileMethodOverloads2.js, 8, 22))
>this : Symbol(Example, Decl(jsFileMethodOverloads2.js, 0, 0))
>value : Symbol(Example.value, Decl(jsFileMethodOverloads2.js, 8, 22))
}
}

View File

@ -0,0 +1,73 @@
=== tests/cases/compiler/jsFileMethodOverloads2.js ===
// Also works if all @overload tags are combined in one comment.
/**
* @template T
*/
class Example {
>Example : Example<T>
/**
* @param {T} value
*/
constructor(value) {
>value : T
this.value = value;
>this.value = value : T
>this.value : any
>this : this
>value : any
>value : T
}
/**
* @overload
* @param {Example<number>} this
* @returns {'number'}
*
* @overload
* @param {Example<string>} this
* @returns {'string'}
*
* @returns {string}
*/
getTypeName() {
>getTypeName : { (this: Example<number>): 'number'; (this: Example<string>): 'string'; }
return typeof this.value;
>typeof this.value : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
>this.value : T
>this : this
>value : T
}
/**
* @template U
* @overload
* @param {(y: T) => U} fn
* @returns {U}
*
* @overload
* @returns {T}
*
* @param {(y: T) => unknown} [fn]
* @returns {unknown}
*/
transform(fn) {
>transform : { <U>(fn: (y: T) => U): U; <U>(): T; }
>fn : (y: T) => unknown
return fn ? fn(this.value) : this.value;
>fn ? fn(this.value) : this.value : unknown
>fn : (y: T) => unknown
>fn(this.value) : unknown
>fn : (y: T) => unknown
>this.value : T
>this : this
>value : T
>this.value : T
>this : this
>value : T
}
}

View File

@ -0,0 +1,17 @@
/*====== /tests/cases/fourslash/foo.js ======*/
/**
* @overload
* @param {number} x
* @returns {number}
*
* @overload
* @param {string} x
* @returns {string}
*
* @param {unknown} RENAME
* @returns {unknown}
*/
function foo([|RENAME|]) {
return RENAME;
}

View File

@ -0,0 +1,56 @@
// @allowJs: true
// @outDir: dist/
// @declaration: true
// @filename: jsFileAlternativeUseOfOverloadTag.js
// These are a few examples of existing alternative uses of @overload tag.
// They will not work as expected with our implementation, but we are
// trying to make sure that our changes do not result in any crashes here.
const example1 = {
/**
* @overload Example1(value)
* Creates Example1
* @param value [String]
*/
constructor: function Example1(value, options) {},
};
const example2 = {
/**
* Example 2
*
* @overload Example2(value)
* Creates Example2
* @param value [String]
* @param secretAccessKey [String]
* @param sessionToken [String]
* @example Creates with string value
* const example = new Example('');
* @overload Example2(options)
* Creates Example2
* @option options value [String]
* @example Creates with options object
* const example = new Example2({
* value: '',
* });
*/
constructor: function Example2() {},
};
const example3 = {
/**
* @overload evaluate(options = {}, [callback])
* Evaluate something
* @note Something interesting
* @param options [map]
* @return [string] returns evaluation result
* @return [null] returns nothing if callback provided
* @callback callback function (error, result)
* If callback is provided it will be called with evaluation result
* @param error [Error]
* @param result [String]
* @see callback
*/
evaluate: function evaluate(options, callback) {},
};

View File

@ -0,0 +1,62 @@
// @allowJs: true
// @outDir: dist/
// @declaration: true
// @filename: jsFileFunctionOverloads.js
/**
* @overload
* @param {number} x
* @returns {'number'}
*/
/**
* @overload
* @param {string} x
* @returns {'string'}
*/
/**
* @overload
* @param {boolean} x
* @returns {'boolean'}
*/
/**
* @param {unknown} x
* @returns {string}
*/
function getTypeName(x) {
return typeof x;
}
/**
* @template T
* @param {T} x
* @returns {T}
*/
const identity = x => x;
/**
* @template T
* @template U
* @overload
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*/
/**
* @template T
* @overload
* @param {T[][]} array
* @returns {T[]}
*/
/**
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable = identity) {
/** @type {unknown[]} */
const result = [];
for (let i = 0; i < array.length; i += 1) {
result.push(.../** @type {unknown[]} */(iterable(array[i])));
}
return result;
}

View File

@ -0,0 +1,57 @@
// @allowJs: true
// @outDir: dist/
// @declaration: true
// @filename: jsFileFunctionOverloads2.js
// Also works if all @overload tags are combined in one comment.
/**
* @overload
* @param {number} x
* @returns {'number'}
*
* @overload
* @param {string} x
* @returns {'string'}
*
* @overload
* @param {boolean} x
* @returns {'boolean'}
*
* @param {unknown} x
* @returns {string}
*/
function getTypeName(x) {
return typeof x;
}
/**
* @template T
* @param {T} x
* @returns {T}
*/
const identity = x => x;
/**
* @template T
* @template U
* @overload
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*
* @overload
* @param {T[][]} array
* @returns {T[]}
*
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable = identity) {
/** @type {unknown[]} */
const result = [];
for (let i = 0; i < array.length; i += 1) {
result.push(.../** @type {unknown[]} */(iterable(array[i])));
}
return result;
}

View File

@ -0,0 +1,51 @@
// @allowJs: true
// @outDir: dist/
// @declaration: true
// @filename: jsFileMethodOverloads.js
/**
* @template T
*/
class Example {
/**
* @param {T} value
*/
constructor(value) {
this.value = value;
}
/**
* @overload
* @param {Example<number>} this
* @returns {'number'}
*/
/**
* @overload
* @param {Example<string>} this
* @returns {'string'}
*/
/**
* @returns {string}
*/
getTypeName() {
return typeof this.value;
}
/**
* @template U
* @overload
* @param {(y: T) => U} fn
* @returns {U}
*/
/**
* @overload
* @returns {T}
*/
/**
* @param {(y: T) => unknown} [fn]
* @returns {unknown}
*/
transform(fn) {
return fn ? fn(this.value) : this.value;
}
}

View File

@ -0,0 +1,48 @@
// @allowJs: true
// @outDir: dist/
// @declaration: true
// @filename: jsFileMethodOverloads2.js
// Also works if all @overload tags are combined in one comment.
/**
* @template T
*/
class Example {
/**
* @param {T} value
*/
constructor(value) {
this.value = value;
}
/**
* @overload
* @param {Example<number>} this
* @returns {'number'}
*
* @overload
* @param {Example<string>} this
* @returns {'string'}
*
* @returns {string}
*/
getTypeName() {
return typeof this.value;
}
/**
* @template U
* @overload
* @param {(y: T) => U} fn
* @returns {U}
*
* @overload
* @returns {T}
*
* @param {(y: T) => unknown} [fn]
* @returns {unknown}
*/
transform(fn) {
return fn ? fn(this.value) : this.value;
}
}

View File

@ -0,0 +1,22 @@
/// <reference path="fourslash.ts" />
// @allowJs: true
// @checkJs: true
// @Filename: foo.js
/////**
//// * @overload
//// * @param {number} x
//// * @returns {number}
//// *
//// * @overload
//// * @param {string} x
//// * @returns {string}
//// *
//// * @param {unknown} x
//// * @returns {unknown}
//// */
////function foo(x/*1*/) {
//// return x;
////}
verify.baselineFindAllReferences("1");

View File

@ -0,0 +1,22 @@
/// <reference path='fourslash.ts'/>
// @allowJs: true
// @checkJs: true
// @Filename: foo.js
/////**
//// * @overload
//// * @param {number} x
//// * @returns {number}
//// *
//// * @overload
//// * @param {string} x
//// * @returns {string}
//// *
//// * @param {unknown} x
//// * @returns {unknown}
//// */
////function foo(x/**/) {
//// return x;
////}
verify.baselineRename("", {});