Fix @param type parameter lookup (#39532)

Previously, getObjectTypeInstantiation had special-case code to look up
type parameters for `@param` as if they were in the parameter location.

This should occur in the main lookup loop of `getOuterTypeParameters`,
however. The current code only runs once, which is not sufficient, and
it also jumps to the parameter for any type contained in a `@param`,
which skips type parameters that occur in the tag itself.
This commit is contained in:
Nathan Shively-Sanders 2020-07-10 08:42:25 -07:00 committed by GitHub
parent b397d1fd4a
commit 3b107fec3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 12 deletions

View File

@ -8758,6 +8758,12 @@ namespace ts {
(node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.InterfaceDeclaration || isJSConstructor(node)) &&
getDeclaredTypeOfClassOrInterface(getSymbolOfNode(node as ClassLikeDeclaration | InterfaceDeclaration)).thisType;
return thisType ? append(outerAndOwnTypeParameters, thisType) : outerAndOwnTypeParameters;
case SyntaxKind.JSDocParameterTag:
const paramSymbol = getParameterSymbolFromJSDoc(node as JSDocParameterTag);
if (paramSymbol) {
node = paramSymbol.valueDeclaration;
}
break;
}
}
}
@ -14584,24 +14590,14 @@ namespace ts {
function getObjectTypeInstantiation(type: AnonymousType | DeferredTypeReference, mapper: TypeMapper) {
const target = type.objectFlags & ObjectFlags.Instantiated ? type.target! : type;
const node = type.objectFlags & ObjectFlags.Reference ? (<TypeReference>type).node! : type.symbol.declarations[0];
const links = getNodeLinks(node);
const declaration = type.objectFlags & ObjectFlags.Reference ? (<TypeReference>type).node! : type.symbol.declarations[0];
const links = getNodeLinks(declaration);
let typeParameters = links.outerTypeParameters;
if (!typeParameters) {
// The first time an anonymous type is instantiated we compute and store a list of the type
// parameters that are in scope (and therefore potentially referenced). For type literals that
// aren't the right hand side of a generic type alias declaration we optimize by reducing the
// set of type parameters to those that are possibly referenced in the literal.
let declaration = node;
if (isInJSFile(declaration)) {
const paramTag = findAncestor(declaration, isJSDocParameterTag);
if (paramTag) {
const paramSymbol = getParameterSymbolFromJSDoc(paramTag);
if (paramSymbol) {
declaration = paramSymbol.valueDeclaration;
}
}
}
let outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true);
if (isJSConstructor(declaration)) {
const templateTagParameters = getTypeParametersFromDeclaration(declaration as DeclarationWithTypeParameters);

View File

@ -0,0 +1,21 @@
=== tests/cases/conformance/jsdoc/38572.js ===
/**
* @template T
* @param {T} a
* @param {{[K in keyof T]: (value: T[K]) => void }} b
*/
function f(a, b) {
>f : Symbol(f, Decl(38572.js, 0, 0))
>a : Symbol(a, Decl(38572.js, 5, 11))
>b : Symbol(b, Decl(38572.js, 5, 13))
}
f({ x: 42 }, { x(param) { param.toFixed() } });
>f : Symbol(f, Decl(38572.js, 0, 0))
>x : Symbol(x, Decl(38572.js, 8, 3))
>x : Symbol(x, Decl(38572.js, 8, 14))
>param : Symbol(param, Decl(38572.js, 8, 17))
>param.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))
>param : Symbol(param, Decl(38572.js, 8, 17))
>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))

View File

@ -0,0 +1,26 @@
=== tests/cases/conformance/jsdoc/38572.js ===
/**
* @template T
* @param {T} a
* @param {{[K in keyof T]: (value: T[K]) => void }} b
*/
function f(a, b) {
>f : <T>(a: T, b: { [K in keyof T]: (value: T[K]) => void; }) => void
>a : T
>b : { [K in keyof T]: (value: T[K]) => void; }
}
f({ x: 42 }, { x(param) { param.toFixed() } });
>f({ x: 42 }, { x(param) { param.toFixed() } }) : void
>f : <T>(a: T, b: { [K in keyof T]: (value: T[K]) => void; }) => void
>{ x: 42 } : { x: number; }
>x : number
>42 : 42
>{ x(param) { param.toFixed() } } : { x(param: number): void; }
>x : (param: number) => void
>param : number
>param.toFixed() : string
>param.toFixed : (fractionDigits?: number) => string
>param : number
>toFixed : (fractionDigits?: number) => string

View File

@ -0,0 +1,14 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @Filename: 38572.js
/**
* @template T
* @param {T} a
* @param {{[K in keyof T]: (value: T[K]) => void }} b
*/
function f(a, b) {
}
f({ x: 42 }, { x(param) { param.toFixed() } });