Skip to content

Commit a2e4a28

Browse files
authored
Get [type] parameter types from @type tag (microsoft#26694)
* 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 microsoft#25618 * Fix split ifs according to PR comments
1 parent 4cf5774 commit a2e4a28

File tree

5 files changed

+65
-1
lines changed

5 files changed

+65
-1
lines changed

src/compiler/checker.ts

+6
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

+14-1
Original file line numberDiff line numberDiff line change
@@ -5116,7 +5116,20 @@ namespace ts {
51165116
Debug.assert(node.parent.kind === SyntaxKind.JSDocComment);
51175117
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined) as ReadonlyArray<TypeParameterDeclaration>;
51185118
}
5119-
return node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : emptyArray);
5119+
if (node.typeParameters) {
5120+
return node.typeParameters;
5121+
}
5122+
if (isInJavaScriptFile(node)) {
5123+
const decls = getJSDocTypeParameterDeclarations(node);
5124+
if (decls.length) {
5125+
return decls;
5126+
}
5127+
const typeTag = getJSDocType(node);
5128+
if (typeTag && isFunctionTypeNode(typeTag) && typeTag.typeParameters) {
5129+
return typeTag.typeParameters;
5130+
}
5131+
}
5132+
return emptyArray;
51205133
}
51215134

51225135
export function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined {
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+
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+
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)