mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-07 05:41:22 -06:00
Merge pull request #16463 from Microsoft/jsdoc-@template-in-scope-as-type-parameter
Jsdoc @template in scope as type parameter
This commit is contained in:
commit
3d8cf62846
@ -6170,24 +6170,16 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getTypeParametersFromJSDocTemplate(declaration: SignatureDeclaration): TypeParameter[] {
|
||||
if (declaration.flags & NodeFlags.JavaScriptFile) {
|
||||
const templateTag = getJSDocTemplateTag(declaration);
|
||||
if (templateTag) {
|
||||
return getTypeParametersFromDeclaration(templateTag.typeParameters);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual
|
||||
// type checking functions).
|
||||
function getTypeParametersFromDeclaration(typeParameterDeclarations: TypeParameterDeclaration[]): TypeParameter[] {
|
||||
const result: TypeParameter[] = [];
|
||||
forEach(typeParameterDeclarations, node => {
|
||||
function getTypeParametersFromDeclaration(declaration: DeclarationWithTypeParameters): TypeParameter[] {
|
||||
let result: TypeParameter[];
|
||||
forEach(getEffectiveTypeParameterDeclarations(declaration), node => {
|
||||
const tp = getDeclaredTypeOfTypeParameter(node.symbol);
|
||||
if (!contains(result, tp)) {
|
||||
if (!result) {
|
||||
result = [];
|
||||
}
|
||||
result.push(tp);
|
||||
}
|
||||
});
|
||||
@ -6383,9 +6375,7 @@ namespace ts {
|
||||
const classType = declaration.kind === SyntaxKind.Constructor ?
|
||||
getDeclaredTypeOfClassOrInterface(getMergedSymbol((<ClassDeclaration>declaration.parent).symbol))
|
||||
: undefined;
|
||||
const typeParameters = classType ? classType.localTypeParameters :
|
||||
declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) :
|
||||
getTypeParametersFromJSDocTemplate(declaration);
|
||||
const typeParameters = classType ? classType.localTypeParameters : getTypeParametersFromDeclaration(declaration);
|
||||
const returnType = getSignatureReturnTypeFromDeclaration(declaration, isJSConstructSignature, classType);
|
||||
const typePredicate = declaration.type && declaration.type.kind === SyntaxKind.TypePredicate ?
|
||||
createTypePredicateFromTypePredicateNode(declaration.type as TypePredicateNode) :
|
||||
@ -8166,9 +8156,9 @@ namespace ts {
|
||||
case SyntaxKind.ClassExpression:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
const declaration = node as DeclarationWithTypeParameters;
|
||||
if (declaration.typeParameters) {
|
||||
for (const d of declaration.typeParameters) {
|
||||
const typeParameters = getEffectiveTypeParameterDeclarations(node as DeclarationWithTypeParameters);
|
||||
if (typeParameters) {
|
||||
for (const d of typeParameters) {
|
||||
if (contains(mappedTypes, getDeclaredTypeOfTypeParameter(getSymbolOfNode(d)))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1448,7 +1448,7 @@ namespace ts {
|
||||
return node && firstOrUndefined(getJSDocTags(node, kind));
|
||||
}
|
||||
|
||||
export function getJSDocs(node: Node): (JSDoc | JSDocTag)[] {
|
||||
export function getJSDocs(node: Node): (JSDoc | JSDocTag)[] {
|
||||
if (isJSDocTypedefTag(node)) {
|
||||
return [node.parent];
|
||||
}
|
||||
@ -2743,6 +2743,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the effective type parameters. If the node was parsed in a
|
||||
* JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
|
||||
*/
|
||||
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): TypeParameterDeclaration[] {
|
||||
if (node.typeParameters) {
|
||||
return node.typeParameters;
|
||||
}
|
||||
if (node.flags & NodeFlags.JavaScriptFile) {
|
||||
const templateTag = getJSDocTemplateTag(node);
|
||||
return templateTag && templateTag.typeParameters;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the effective type annotation of the value parameter of a set accessor. If the node
|
||||
* was parsed in a JavaScript file, gets the type annotation from JSDoc.
|
||||
|
||||
36
tests/baselines/reference/jsdocTemplateTag.symbols
Normal file
36
tests/baselines/reference/jsdocTemplateTag.symbols
Normal file
@ -0,0 +1,36 @@
|
||||
=== tests/cases/conformance/jsdoc/jsdocTemplateTag.ts ===
|
||||
/**
|
||||
* @param {T} a
|
||||
* @template T
|
||||
*/
|
||||
function f<T>(a: T) {
|
||||
>f : Symbol(f, Decl(jsdocTemplateTag.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(jsdocTemplateTag.ts, 4, 11))
|
||||
>a : Symbol(a, Decl(jsdocTemplateTag.ts, 4, 14))
|
||||
>T : Symbol(T, Decl(jsdocTemplateTag.ts, 4, 11))
|
||||
|
||||
return () => a
|
||||
>a : Symbol(a, Decl(jsdocTemplateTag.ts, 4, 14))
|
||||
}
|
||||
let n = f(1)()
|
||||
>n : Symbol(n, Decl(jsdocTemplateTag.ts, 7, 3))
|
||||
>f : Symbol(f, Decl(jsdocTemplateTag.ts, 0, 0))
|
||||
|
||||
/**
|
||||
* @param {T} a
|
||||
* @template T
|
||||
* @returns {function(): T}
|
||||
*/
|
||||
function g<T>(a: T) {
|
||||
>g : Symbol(g, Decl(jsdocTemplateTag.ts, 7, 14))
|
||||
>T : Symbol(T, Decl(jsdocTemplateTag.ts, 14, 11))
|
||||
>a : Symbol(a, Decl(jsdocTemplateTag.ts, 14, 14))
|
||||
>T : Symbol(T, Decl(jsdocTemplateTag.ts, 14, 11))
|
||||
|
||||
return () => a
|
||||
>a : Symbol(a, Decl(jsdocTemplateTag.ts, 14, 14))
|
||||
}
|
||||
let s = g('hi')()
|
||||
>s : Symbol(s, Decl(jsdocTemplateTag.ts, 17, 3))
|
||||
>g : Symbol(g, Decl(jsdocTemplateTag.ts, 7, 14))
|
||||
|
||||
44
tests/baselines/reference/jsdocTemplateTag.types
Normal file
44
tests/baselines/reference/jsdocTemplateTag.types
Normal file
@ -0,0 +1,44 @@
|
||||
=== tests/cases/conformance/jsdoc/jsdocTemplateTag.ts ===
|
||||
/**
|
||||
* @param {T} a
|
||||
* @template T
|
||||
*/
|
||||
function f<T>(a: T) {
|
||||
>f : <T>(a: T) => () => T
|
||||
>T : T
|
||||
>a : T
|
||||
>T : T
|
||||
|
||||
return () => a
|
||||
>() => a : () => T
|
||||
>a : T
|
||||
}
|
||||
let n = f(1)()
|
||||
>n : number
|
||||
>f(1)() : number
|
||||
>f(1) : () => number
|
||||
>f : <T>(a: T) => () => T
|
||||
>1 : 1
|
||||
|
||||
/**
|
||||
* @param {T} a
|
||||
* @template T
|
||||
* @returns {function(): T}
|
||||
*/
|
||||
function g<T>(a: T) {
|
||||
>g : <T>(a: T) => () => T
|
||||
>T : T
|
||||
>a : T
|
||||
>T : T
|
||||
|
||||
return () => a
|
||||
>() => a : () => T
|
||||
>a : T
|
||||
}
|
||||
let s = g('hi')()
|
||||
>s : string
|
||||
>g('hi')() : string
|
||||
>g('hi') : () => string
|
||||
>g : <T>(a: T) => () => T
|
||||
>'hi' : "hi"
|
||||
|
||||
21
tests/cases/conformance/jsdoc/jsdocTemplateTag.ts
Normal file
21
tests/cases/conformance/jsdoc/jsdocTemplateTag.ts
Normal file
@ -0,0 +1,21 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noEmit: true
|
||||
/**
|
||||
* @param {T} a
|
||||
* @template T
|
||||
*/
|
||||
function f<T>(a: T) {
|
||||
return () => a
|
||||
}
|
||||
let n = f(1)()
|
||||
|
||||
/**
|
||||
* @param {T} a
|
||||
* @template T
|
||||
* @returns {function(): T}
|
||||
*/
|
||||
function g<T>(a: T) {
|
||||
return () => a
|
||||
}
|
||||
let s = g('hi')()
|
||||
Loading…
x
Reference in New Issue
Block a user