From a2e4a282e799fe724e86e06a18157e7aca14392e Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 27 Aug 2018 16:52:35 -0700 Subject: [PATCH] Get [type] parameter types from @type tag (#26694) * Get [type] parameter types from @type tag Previously only the return type was used in cases like this: ```js /** @type {(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 * Fix split ifs according to PR comments --- src/compiler/checker.ts | 6 ++++++ src/compiler/utilities.ts | 15 ++++++++++++++- .../typeTagWithGenericSignature.symbols | 15 +++++++++++++++ .../reference/typeTagWithGenericSignature.types | 17 +++++++++++++++++ .../jsdoc/typeTagWithGenericSignature.ts | 13 +++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/typeTagWithGenericSignature.symbols create mode 100644 tests/baselines/reference/typeTagWithGenericSignature.types create mode 100644 tests/cases/conformance/jsdoc/typeTagWithGenericSignature.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9c0f3cd643f..679cb79e0cf 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 87cf26a1927..6b905ad65ca 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -5116,7 +5116,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 00000000000..c9a699d3b4a --- /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 00000000000..585fd49fbf4 --- /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 00000000000..04ef3e5e1a0 --- /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); +