diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a551108f75ca8..94fc168c7c5fc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4699,6 +4699,12 @@ namespace ts { return getReturnTypeOfSignature(getterSignature); } } + if (isInJavaScriptFile(declaration)) { + const typeTag = getJSDocType(func); + if (typeTag && isFunctionTypeNode(typeTag)) { + return getTypeAtPosition(getSignatureFromDeclaration(typeTag), func.parameters.indexOf(declaration)); + } + } // Use contextual parameter type if one is available const type = declaration.symbol.escapedName === InternalSymbolName.This ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration); if (type) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 33dfd2617c979..7f65025d7fb3b 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -5120,7 +5120,20 @@ namespace ts { Debug.assert(node.parent.kind === SyntaxKind.JSDocComment); return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined) as ReadonlyArray; } - return node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : emptyArray); + if (node.typeParameters) { + return node.typeParameters; + } + if (isInJavaScriptFile(node)) { + const decls = getJSDocTypeParameterDeclarations(node); + if (decls.length) { + return decls; + } + const typeTag = getJSDocType(node); + if (typeTag && isFunctionTypeNode(typeTag) && typeTag.typeParameters) { + return typeTag.typeParameters; + } + } + return emptyArray; } export function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined { diff --git a/tests/baselines/reference/typeTagWithGenericSignature.symbols b/tests/baselines/reference/typeTagWithGenericSignature.symbols new file mode 100644 index 0000000000000..c9a699d3b4a6f --- /dev/null +++ b/tests/baselines/reference/typeTagWithGenericSignature.symbols @@ -0,0 +1,15 @@ +=== tests/cases/conformance/jsdoc/bug25618.js === +/** @type {(param?: T) => T | undefined} */ +function typed(param) { +>typed : Symbol(typed, Decl(bug25618.js, 0, 0)) +>param : Symbol(param, Decl(bug25618.js, 1, 15)) + + return param; +>param : Symbol(param, Decl(bug25618.js, 1, 15)) +} + +var n = typed(1); +>n : Symbol(n, Decl(bug25618.js, 5, 3)) +>typed : Symbol(typed, Decl(bug25618.js, 0, 0)) + + diff --git a/tests/baselines/reference/typeTagWithGenericSignature.types b/tests/baselines/reference/typeTagWithGenericSignature.types new file mode 100644 index 0000000000000..585fd49fbf48b --- /dev/null +++ b/tests/baselines/reference/typeTagWithGenericSignature.types @@ -0,0 +1,17 @@ +=== tests/cases/conformance/jsdoc/bug25618.js === +/** @type {(param?: T) => T | undefined} */ +function typed(param) { +>typed : (param: T | undefined) => T | undefined +>param : T | undefined + + return param; +>param : T | undefined +} + +var n = typed(1); +>n : number | undefined +>typed(1) : 1 | undefined +>typed : (param: T | undefined) => T | undefined +>1 : 1 + + diff --git a/tests/cases/conformance/jsdoc/typeTagWithGenericSignature.ts b/tests/cases/conformance/jsdoc/typeTagWithGenericSignature.ts new file mode 100644 index 0000000000000..04ef3e5e1a05d --- /dev/null +++ b/tests/cases/conformance/jsdoc/typeTagWithGenericSignature.ts @@ -0,0 +1,13 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true +// @strict: true +// @Filename: bug25618.js + +/** @type {(param?: T) => T | undefined} */ +function typed(param) { + return param; +} + +var n = typed(1); +