Skip to content

Commit ed8949e

Browse files
committed
Get [type] parameter types from @type tag
Previously only the return type was used in cases like this: ```js /** @type {<T>(param?: T) => T | undefined} */ function g(param) { return param; } ``` Now the type parameters from the type tag are used, and the compiler gets the type of the parameter by using the position in the signature of the type tag. Fixes #25618
1 parent 0a59da1 commit ed8949e

File tree

5 files changed

+67
-1
lines changed

5 files changed

+67
-1
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4699,6 +4699,12 @@ namespace ts {
46994699
return getReturnTypeOfSignature(getterSignature);
47004700
}
47014701
}
4702+
if (isInJavaScriptFile(declaration)) {
4703+
const typeTag = getJSDocType(func);
4704+
if (typeTag && isFunctionTypeNode(typeTag)) {
4705+
return getTypeAtPosition(getSignatureFromDeclaration(typeTag), func.parameters.indexOf(declaration));
4706+
}
4707+
}
47024708
// Use contextual parameter type if one is available
47034709
const type = declaration.symbol.escapedName === InternalSymbolName.This ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration);
47044710
if (type) {

src/compiler/utilities.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5120,7 +5120,22 @@ namespace ts {
51205120
Debug.assert(node.parent.kind === SyntaxKind.JSDocComment);
51215121
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined) as ReadonlyArray<TypeParameterDeclaration>;
51225122
}
5123-
return node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : emptyArray);
5123+
if (node.typeParameters) {
5124+
return node.typeParameters;
5125+
}
5126+
if (isInJavaScriptFile(node)) {
5127+
const decls = getJSDocTypeParameterDeclarations(node);
5128+
if (decls.length) {
5129+
return decls;
5130+
}
5131+
const typeTag = getJSDocType(node);
5132+
if (typeTag) {
5133+
if (isFunctionTypeNode(typeTag) && typeTag.typeParameters) {
5134+
return typeTag.typeParameters;
5135+
}
5136+
}
5137+
}
5138+
return emptyArray;
51245139
}
51255140

51265141
export function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/conformance/jsdoc/bug25618.js ===
2+
/** @type {<T>(param?: T) => T | undefined} */
3+
function typed(param) {
4+
>typed : Symbol(typed, Decl(bug25618.js, 0, 0))
5+
>param : Symbol(param, Decl(bug25618.js, 1, 15))
6+
7+
return param;
8+
>param : Symbol(param, Decl(bug25618.js, 1, 15))
9+
}
10+
11+
var n = typed(1);
12+
>n : Symbol(n, Decl(bug25618.js, 5, 3))
13+
>typed : Symbol(typed, Decl(bug25618.js, 0, 0))
14+
15+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/conformance/jsdoc/bug25618.js ===
2+
/** @type {<T>(param?: T) => T | undefined} */
3+
function typed(param) {
4+
>typed : <T>(param: T | undefined) => T | undefined
5+
>param : T | undefined
6+
7+
return param;
8+
>param : T | undefined
9+
}
10+
11+
var n = typed(1);
12+
>n : number | undefined
13+
>typed(1) : 1 | undefined
14+
>typed : <T>(param: T | undefined) => T | undefined
15+
>1 : 1
16+
17+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @checkJs: true
2+
// @allowJs: true
3+
// @noEmit: true
4+
// @strict: true
5+
// @Filename: bug25618.js
6+
7+
/** @type {<T>(param?: T) => T | undefined} */
8+
function typed(param) {
9+
return param;
10+
}
11+
12+
var n = typed(1);
13+

0 commit comments

Comments
 (0)