mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 04:43:37 -05:00
In JS, class supports @template tag for declaring type parameters (#23511)
* Support @template as a class type parameter Still need to do the following: 1. Correctly get jsdoc host in predicate. 2. Make this work for constructor functions too. 3. Scan rest of codebase for other usages of the type parameters property that should be calls to getEffectiveTypeParameterDeclarations. 4. Rename tp to something more readable, like typar or ts'. * Use jsdoc host declaration to find container * Longer names for type parameters * Fix renaming operation * Update fourslash test * Support @template for JS constructors * Look for both outer and tag type parameters * Improve naming to improve code clarity
This commit is contained in:
committed by
GitHub
parent
84b12910e8
commit
8d969a23cb
@@ -1554,7 +1554,8 @@ namespace ts {
|
||||
|
||||
function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) {
|
||||
for (const decl of symbol.declarations) {
|
||||
if (decl.kind === SyntaxKind.TypeParameter && decl.parent === container) {
|
||||
const parent = isJSDocTemplateTag(decl.parent) ? getJSDocHost(decl.parent) : decl.parent;
|
||||
if (decl.kind === SyntaxKind.TypeParameter && parent === container) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2060,10 +2061,10 @@ namespace ts {
|
||||
let symbol: Symbol;
|
||||
if (name.kind === SyntaxKind.Identifier) {
|
||||
const message = meaning === namespaceMeaning ? Diagnostics.Cannot_find_namespace_0 : Diagnostics.Cannot_find_name_0;
|
||||
|
||||
symbol = resolveName(location || name, name.escapedText, meaning, ignoreErrors ? undefined : message, name, /*isUse*/ true);
|
||||
const symbolFromJSPrototype = isInJavaScriptFile(name) && resolveEntityNameFromJSPrototype(name, meaning);
|
||||
symbol = resolveName(location || name, name.escapedText, meaning, ignoreErrors || symbolFromJSPrototype ? undefined : message, name, /*isUse*/ true);
|
||||
if (!symbol) {
|
||||
return undefined;
|
||||
return symbolFromJSPrototype;
|
||||
}
|
||||
}
|
||||
else if (name.kind === SyntaxKind.QualifiedName || name.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
@@ -2114,6 +2115,18 @@ namespace ts {
|
||||
return (symbol.flags & meaning) || dontResolveAlias ? symbol : resolveAlias(symbol);
|
||||
}
|
||||
|
||||
function resolveEntityNameFromJSPrototype(name: Identifier, meaning: SymbolFlags) {
|
||||
if (isJSDocTypeReference(name.parent) && isJSDocTag(name.parent.parent.parent)) {
|
||||
const host = getJSDocHost(name.parent.parent.parent as JSDocTag);
|
||||
if (isExpressionStatement(host) &&
|
||||
isBinaryExpression(host.expression) &&
|
||||
getSpecialPropertyAssignmentKind(host.expression) === SpecialPropertyAssignmentKind.PrototypeProperty) {
|
||||
const secondaryLocation = getSymbolOfNode(host.expression.left).parent.valueDeclaration;
|
||||
return resolveName(secondaryLocation, name.escapedText, meaning, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resolveExternalModuleName(location: Node, moduleReferenceExpression: Expression): Symbol {
|
||||
return resolveExternalModuleNameWorker(location, moduleReferenceExpression, Diagnostics.Cannot_find_module_0);
|
||||
}
|
||||
@@ -4897,8 +4910,7 @@ namespace ts {
|
||||
// in-place and returns the same array.
|
||||
function appendTypeParameters(typeParameters: TypeParameter[], declarations: ReadonlyArray<TypeParameterDeclaration>): TypeParameter[] {
|
||||
for (const declaration of declarations) {
|
||||
const tp = getDeclaredTypeOfTypeParameter(getSymbolOfNode(declaration));
|
||||
typeParameters = appendIfUnique(typeParameters, tp);
|
||||
typeParameters = appendIfUnique(typeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfNode(declaration)));
|
||||
}
|
||||
return typeParameters;
|
||||
}
|
||||
@@ -4958,8 +4970,9 @@ namespace ts {
|
||||
if (node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.ClassDeclaration ||
|
||||
node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.TypeAliasDeclaration) {
|
||||
const declaration = <InterfaceDeclaration | TypeAliasDeclaration>node;
|
||||
if (declaration.typeParameters) {
|
||||
result = appendTypeParameters(result, declaration.typeParameters);
|
||||
const typeParameters = getEffectiveTypeParameterDeclarations(declaration);
|
||||
if (typeParameters) {
|
||||
result = appendTypeParameters(result, typeParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5455,9 +5468,10 @@ namespace ts {
|
||||
*/
|
||||
function isThislessFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean {
|
||||
const returnType = getEffectiveReturnTypeNode(node);
|
||||
const typeParameters = getEffectiveTypeParameterDeclarations(node);
|
||||
return (node.kind === SyntaxKind.Constructor || (returnType && isThislessType(returnType))) &&
|
||||
node.parameters.every(isThislessVariableLikeDeclaration) &&
|
||||
(!node.typeParameters || node.typeParameters.every(isThislessTypeParameter));
|
||||
(!typeParameters || typeParameters.every(isThislessTypeParameter));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6735,8 +6749,7 @@ namespace ts {
|
||||
function getTypeParametersFromDeclaration(declaration: DeclarationWithTypeParameters): TypeParameter[] {
|
||||
let result: TypeParameter[];
|
||||
forEach(getEffectiveTypeParameterDeclarations(declaration), node => {
|
||||
const tp = getDeclaredTypeOfTypeParameter(node.symbol);
|
||||
result = appendIfUnique(result, tp);
|
||||
result = appendIfUnique(result, getDeclaredTypeOfTypeParameter(node.symbol));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
@@ -7547,7 +7560,7 @@ namespace ts {
|
||||
return constraints ? getSubstitutionType(typeVariable, getIntersectionType(append(constraints, typeVariable))) : typeVariable;
|
||||
}
|
||||
|
||||
function isJSDocTypeReference(node: NodeWithTypeArguments): node is TypeReferenceNode {
|
||||
function isJSDocTypeReference(node: Node): node is TypeReferenceNode {
|
||||
return node.flags & NodeFlags.JSDoc && node.kind === SyntaxKind.TypeReference;
|
||||
}
|
||||
|
||||
@@ -9170,10 +9183,15 @@ namespace ts {
|
||||
// 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.
|
||||
const declaration = symbol.declarations[0];
|
||||
const outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true) || emptyArray;
|
||||
let outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true);
|
||||
if (isJavaScriptConstructor(declaration)) {
|
||||
const templateTagParameters = getTypeParametersFromDeclaration(declaration as DeclarationWithTypeParameters);
|
||||
outerTypeParameters = addRange(outerTypeParameters, templateTagParameters);
|
||||
}
|
||||
typeParameters = outerTypeParameters || emptyArray;
|
||||
typeParameters = symbol.flags & SymbolFlags.TypeLiteral && !target.aliasTypeArguments ?
|
||||
filter(outerTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, declaration)) :
|
||||
outerTypeParameters;
|
||||
filter(typeParameters, tp => isTypeParameterPossiblyReferenced(tp, declaration)) :
|
||||
typeParameters;
|
||||
links.outerTypeParameters = typeParameters;
|
||||
if (typeParameters.length) {
|
||||
links.instantiations = createMap<Type>();
|
||||
@@ -18533,7 +18551,7 @@ namespace ts {
|
||||
}
|
||||
const type = funcSymbol && getJavaScriptClassType(funcSymbol);
|
||||
if (type) {
|
||||
return type;
|
||||
return signature.target ? instantiateType(type, signature.mapper) : type;
|
||||
}
|
||||
if (noImplicitAny) {
|
||||
error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type);
|
||||
@@ -22161,8 +22179,9 @@ namespace ts {
|
||||
): void {
|
||||
// Only report errors on the last declaration for the type parameter container;
|
||||
// this ensures that all uses have been accounted for.
|
||||
if (!(node.flags & NodeFlags.Ambient) && node.typeParameters && last(getSymbolOfNode(node)!.declarations) === node) {
|
||||
for (const typeParameter of node.typeParameters) {
|
||||
const typeParameters = getEffectiveTypeParameterDeclarations(node);
|
||||
if (!(node.flags & NodeFlags.Ambient) && typeParameters && last(getSymbolOfNode(node)!.declarations) === node) {
|
||||
for (const typeParameter of typeParameters) {
|
||||
if (!(getMergedSymbol(typeParameter.symbol).isReferenced & SymbolFlags.TypeParameter) && !isIdentifierThatStartsWithUnderScore(typeParameter.name)) {
|
||||
addDiagnostic(UnusedKind.Parameter, createDiagnosticForNode(typeParameter.name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(typeParameter.symbol)));
|
||||
}
|
||||
@@ -23536,20 +23555,21 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function areTypeParametersIdentical(declarations: ReadonlyArray<ClassDeclaration | InterfaceDeclaration>, typeParameters: TypeParameter[]) {
|
||||
const maxTypeArgumentCount = length(typeParameters);
|
||||
const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
|
||||
function areTypeParametersIdentical(declarations: ReadonlyArray<ClassDeclaration | InterfaceDeclaration>, targetParameters: TypeParameter[]) {
|
||||
const maxTypeArgumentCount = length(targetParameters);
|
||||
const minTypeArgumentCount = getMinTypeArgumentCount(targetParameters);
|
||||
|
||||
for (const declaration of declarations) {
|
||||
// If this declaration has too few or too many type parameters, we report an error
|
||||
const numTypeParameters = length(declaration.typeParameters);
|
||||
const sourceParameters = getEffectiveTypeParameterDeclarations(declaration);
|
||||
const numTypeParameters = length(sourceParameters);
|
||||
if (numTypeParameters < minTypeArgumentCount || numTypeParameters > maxTypeArgumentCount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < numTypeParameters; i++) {
|
||||
const source = declaration.typeParameters[i];
|
||||
const target = typeParameters[i];
|
||||
const source = sourceParameters[i];
|
||||
const target = targetParameters[i];
|
||||
|
||||
// If the type parameter node does not have the same as the resolved type
|
||||
// parameter at this position, we report an error.
|
||||
@@ -23610,7 +23630,7 @@ namespace ts {
|
||||
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
|
||||
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
|
||||
}
|
||||
checkTypeParameters(node.typeParameters);
|
||||
checkTypeParameters(getEffectiveTypeParameterDeclarations(node));
|
||||
checkExportsOnMergedDeclarations(node);
|
||||
const symbol = getSymbolOfNode(node);
|
||||
const type = <InterfaceType>getDeclaredTypeOfSymbol(symbol);
|
||||
@@ -26846,7 +26866,7 @@ namespace ts {
|
||||
|
||||
function checkGrammarClassLikeDeclaration(node: ClassLikeDeclaration): boolean {
|
||||
const file = getSourceFileOfNode(node);
|
||||
return checkGrammarClassDeclarationHeritageClauses(node) || checkGrammarTypeParameterList(node.typeParameters, file);
|
||||
return checkGrammarClassDeclarationHeritageClauses(node) || checkGrammarTypeParameterList(getEffectiveTypeParameterDeclarations(node), file);
|
||||
}
|
||||
|
||||
function checkGrammarArrowFunction(node: Node, file: SourceFile): boolean {
|
||||
|
||||
@@ -3055,11 +3055,11 @@ 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): ReadonlyArray<TypeParameterDeclaration> | undefined {
|
||||
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters) {
|
||||
return node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : undefined);
|
||||
}
|
||||
|
||||
export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration> {
|
||||
export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters) {
|
||||
const templateTag = getJSDocTemplateTag(node);
|
||||
return templateTag && templateTag.typeParameters;
|
||||
}
|
||||
|
||||
31
tests/baselines/reference/jsdocTemplateClass.errors.txt
Normal file
31
tests/baselines/reference/jsdocTemplateClass.errors.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
tests/cases/conformance/jsdoc/templateTagOnClasses.js(24,1): error TS2322: Type 'boolean' is not assignable to type 'number'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/templateTagOnClasses.js (1 errors) ====
|
||||
/**
|
||||
* @template {T}
|
||||
* @typedef {(t: T) => T} Id
|
||||
*/
|
||||
class Foo {
|
||||
/** @typedef {(t: T) => T} Id2 */
|
||||
/** @param {T} x */
|
||||
constructor (x) {
|
||||
this.a = x
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {T} x
|
||||
* @param {Id} y
|
||||
* @param {Id2} alpha
|
||||
* @return {T}
|
||||
*/
|
||||
foo(x, y, alpha) {
|
||||
return alpha(y(x))
|
||||
}
|
||||
}
|
||||
var f = new Foo(1)
|
||||
var g = new Foo(false)
|
||||
f.a = g.a
|
||||
~~~
|
||||
!!! error TS2322: Type 'boolean' is not assignable to type 'number'.
|
||||
|
||||
54
tests/baselines/reference/jsdocTemplateClass.symbols
Normal file
54
tests/baselines/reference/jsdocTemplateClass.symbols
Normal file
@@ -0,0 +1,54 @@
|
||||
=== tests/cases/conformance/jsdoc/templateTagOnClasses.js ===
|
||||
/**
|
||||
* @template {T}
|
||||
* @typedef {(t: T) => T} Id
|
||||
*/
|
||||
class Foo {
|
||||
>Foo : Symbol(Foo, Decl(templateTagOnClasses.js, 0, 0))
|
||||
|
||||
/** @typedef {(t: T) => T} Id2 */
|
||||
/** @param {T} x */
|
||||
constructor (x) {
|
||||
>x : Symbol(x, Decl(templateTagOnClasses.js, 7, 17))
|
||||
|
||||
this.a = x
|
||||
>this.a : Symbol(Foo.a, Decl(templateTagOnClasses.js, 7, 21))
|
||||
>this : Symbol(Foo, Decl(templateTagOnClasses.js, 0, 0))
|
||||
>a : Symbol(Foo.a, Decl(templateTagOnClasses.js, 7, 21))
|
||||
>x : Symbol(x, Decl(templateTagOnClasses.js, 7, 17))
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {T} x
|
||||
* @param {Id} y
|
||||
* @param {Id2} alpha
|
||||
* @return {T}
|
||||
*/
|
||||
foo(x, y, alpha) {
|
||||
>foo : Symbol(Foo.foo, Decl(templateTagOnClasses.js, 9, 5))
|
||||
>x : Symbol(x, Decl(templateTagOnClasses.js, 17, 8))
|
||||
>y : Symbol(y, Decl(templateTagOnClasses.js, 17, 10))
|
||||
>alpha : Symbol(alpha, Decl(templateTagOnClasses.js, 17, 13))
|
||||
|
||||
return alpha(y(x))
|
||||
>alpha : Symbol(alpha, Decl(templateTagOnClasses.js, 17, 13))
|
||||
>y : Symbol(y, Decl(templateTagOnClasses.js, 17, 10))
|
||||
>x : Symbol(x, Decl(templateTagOnClasses.js, 17, 8))
|
||||
}
|
||||
}
|
||||
var f = new Foo(1)
|
||||
>f : Symbol(f, Decl(templateTagOnClasses.js, 21, 3))
|
||||
>Foo : Symbol(Foo, Decl(templateTagOnClasses.js, 0, 0))
|
||||
|
||||
var g = new Foo(false)
|
||||
>g : Symbol(g, Decl(templateTagOnClasses.js, 22, 3))
|
||||
>Foo : Symbol(Foo, Decl(templateTagOnClasses.js, 0, 0))
|
||||
|
||||
f.a = g.a
|
||||
>f.a : Symbol(Foo.a, Decl(templateTagOnClasses.js, 7, 21))
|
||||
>f : Symbol(f, Decl(templateTagOnClasses.js, 21, 3))
|
||||
>a : Symbol(Foo.a, Decl(templateTagOnClasses.js, 7, 21))
|
||||
>g.a : Symbol(Foo.a, Decl(templateTagOnClasses.js, 7, 21))
|
||||
>g : Symbol(g, Decl(templateTagOnClasses.js, 22, 3))
|
||||
>a : Symbol(Foo.a, Decl(templateTagOnClasses.js, 7, 21))
|
||||
|
||||
62
tests/baselines/reference/jsdocTemplateClass.types
Normal file
62
tests/baselines/reference/jsdocTemplateClass.types
Normal file
@@ -0,0 +1,62 @@
|
||||
=== tests/cases/conformance/jsdoc/templateTagOnClasses.js ===
|
||||
/**
|
||||
* @template {T}
|
||||
* @typedef {(t: T) => T} Id
|
||||
*/
|
||||
class Foo {
|
||||
>Foo : Foo<T>
|
||||
|
||||
/** @typedef {(t: T) => T} Id2 */
|
||||
/** @param {T} x */
|
||||
constructor (x) {
|
||||
>x : T
|
||||
|
||||
this.a = x
|
||||
>this.a = x : T
|
||||
>this.a : T
|
||||
>this : this
|
||||
>a : T
|
||||
>x : T
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {T} x
|
||||
* @param {Id} y
|
||||
* @param {Id2} alpha
|
||||
* @return {T}
|
||||
*/
|
||||
foo(x, y, alpha) {
|
||||
>foo : (x: T, y: (t: T) => T, alpha: (t: T) => T) => T
|
||||
>x : T
|
||||
>y : (t: T) => T
|
||||
>alpha : (t: T) => T
|
||||
|
||||
return alpha(y(x))
|
||||
>alpha(y(x)) : T
|
||||
>alpha : (t: T) => T
|
||||
>y(x) : T
|
||||
>y : (t: T) => T
|
||||
>x : T
|
||||
}
|
||||
}
|
||||
var f = new Foo(1)
|
||||
>f : Foo<number>
|
||||
>new Foo(1) : Foo<number>
|
||||
>Foo : typeof Foo
|
||||
>1 : 1
|
||||
|
||||
var g = new Foo(false)
|
||||
>g : Foo<boolean>
|
||||
>new Foo(false) : Foo<boolean>
|
||||
>Foo : typeof Foo
|
||||
>false : false
|
||||
|
||||
f.a = g.a
|
||||
>f.a = g.a : boolean
|
||||
>f.a : number
|
||||
>f : Foo<number>
|
||||
>a : number
|
||||
>g.a : boolean
|
||||
>g : Foo<boolean>
|
||||
>a : boolean
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
tests/cases/conformance/jsdoc/templateTagOnConstructorFunctions.js(21,1): error TS2322: Type 'false' is not assignable to type 'number'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/templateTagOnConstructorFunctions.js (1 errors) ====
|
||||
/**
|
||||
* @template {T}
|
||||
* @typedef {(t: T) => T} Id
|
||||
* @param {T} t
|
||||
*/
|
||||
function Zet(t) {
|
||||
/** @type {T} */
|
||||
this.u
|
||||
this.t = t
|
||||
}
|
||||
/**
|
||||
* @param {T} v
|
||||
* @param {Id} id
|
||||
*/
|
||||
Zet.prototype.add = function(v, id) {
|
||||
this.u = v || this.t
|
||||
return id(this.u)
|
||||
}
|
||||
var z = new Zet(1)
|
||||
z.t = 2
|
||||
z.u = false
|
||||
~~~
|
||||
!!! error TS2322: Type 'false' is not assignable to type 'number'.
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
=== tests/cases/conformance/jsdoc/templateTagOnConstructorFunctions.js ===
|
||||
/**
|
||||
* @template {T}
|
||||
* @typedef {(t: T) => T} Id
|
||||
* @param {T} t
|
||||
*/
|
||||
function Zet(t) {
|
||||
>Zet : Symbol(Zet, Decl(templateTagOnConstructorFunctions.js, 0, 0))
|
||||
>t : Symbol(t, Decl(templateTagOnConstructorFunctions.js, 5, 13))
|
||||
|
||||
/** @type {T} */
|
||||
this.u
|
||||
this.t = t
|
||||
>t : Symbol(Zet.t, Decl(templateTagOnConstructorFunctions.js, 7, 10))
|
||||
>t : Symbol(t, Decl(templateTagOnConstructorFunctions.js, 5, 13))
|
||||
}
|
||||
/**
|
||||
* @param {T} v
|
||||
* @param {Id} id
|
||||
*/
|
||||
Zet.prototype.add = function(v, id) {
|
||||
>Zet.prototype : Symbol(Zet.add, Decl(templateTagOnConstructorFunctions.js, 9, 1))
|
||||
>Zet : Symbol(Zet, Decl(templateTagOnConstructorFunctions.js, 0, 0))
|
||||
>prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --))
|
||||
>add : Symbol(Zet.add, Decl(templateTagOnConstructorFunctions.js, 9, 1))
|
||||
>v : Symbol(v, Decl(templateTagOnConstructorFunctions.js, 14, 29))
|
||||
>id : Symbol(id, Decl(templateTagOnConstructorFunctions.js, 14, 31))
|
||||
|
||||
this.u = v || this.t
|
||||
>this.u : Symbol(Zet.u, Decl(templateTagOnConstructorFunctions.js, 5, 17), Decl(templateTagOnConstructorFunctions.js, 14, 37))
|
||||
>this : Symbol(Zet, Decl(templateTagOnConstructorFunctions.js, 0, 0))
|
||||
>u : Symbol(Zet.u, Decl(templateTagOnConstructorFunctions.js, 5, 17), Decl(templateTagOnConstructorFunctions.js, 14, 37))
|
||||
>v : Symbol(v, Decl(templateTagOnConstructorFunctions.js, 14, 29))
|
||||
>this.t : Symbol(Zet.t, Decl(templateTagOnConstructorFunctions.js, 7, 10))
|
||||
>this : Symbol(Zet, Decl(templateTagOnConstructorFunctions.js, 0, 0))
|
||||
>t : Symbol(Zet.t, Decl(templateTagOnConstructorFunctions.js, 7, 10))
|
||||
|
||||
return id(this.u)
|
||||
>id : Symbol(id, Decl(templateTagOnConstructorFunctions.js, 14, 31))
|
||||
>this.u : Symbol(Zet.u, Decl(templateTagOnConstructorFunctions.js, 5, 17), Decl(templateTagOnConstructorFunctions.js, 14, 37))
|
||||
>this : Symbol(Zet, Decl(templateTagOnConstructorFunctions.js, 0, 0))
|
||||
>u : Symbol(Zet.u, Decl(templateTagOnConstructorFunctions.js, 5, 17), Decl(templateTagOnConstructorFunctions.js, 14, 37))
|
||||
}
|
||||
var z = new Zet(1)
|
||||
>z : Symbol(z, Decl(templateTagOnConstructorFunctions.js, 18, 3))
|
||||
>Zet : Symbol(Zet, Decl(templateTagOnConstructorFunctions.js, 0, 0))
|
||||
|
||||
z.t = 2
|
||||
>z.t : Symbol(Zet.t, Decl(templateTagOnConstructorFunctions.js, 7, 10))
|
||||
>z : Symbol(z, Decl(templateTagOnConstructorFunctions.js, 18, 3))
|
||||
>t : Symbol(Zet.t, Decl(templateTagOnConstructorFunctions.js, 7, 10))
|
||||
|
||||
z.u = false
|
||||
>z.u : Symbol(Zet.u, Decl(templateTagOnConstructorFunctions.js, 5, 17), Decl(templateTagOnConstructorFunctions.js, 14, 37))
|
||||
>z : Symbol(z, Decl(templateTagOnConstructorFunctions.js, 18, 3))
|
||||
>u : Symbol(Zet.u, Decl(templateTagOnConstructorFunctions.js, 5, 17), Decl(templateTagOnConstructorFunctions.js, 14, 37))
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
=== tests/cases/conformance/jsdoc/templateTagOnConstructorFunctions.js ===
|
||||
/**
|
||||
* @template {T}
|
||||
* @typedef {(t: T) => T} Id
|
||||
* @param {T} t
|
||||
*/
|
||||
function Zet(t) {
|
||||
>Zet : typeof Zet
|
||||
>t : T
|
||||
|
||||
/** @type {T} */
|
||||
this.u
|
||||
>this.u : any
|
||||
>this : any
|
||||
>u : any
|
||||
|
||||
this.t = t
|
||||
>this.t = t : T
|
||||
>this.t : any
|
||||
>this : any
|
||||
>t : any
|
||||
>t : T
|
||||
}
|
||||
/**
|
||||
* @param {T} v
|
||||
* @param {Id} id
|
||||
*/
|
||||
Zet.prototype.add = function(v, id) {
|
||||
>Zet.prototype.add = function(v, id) { this.u = v || this.t return id(this.u)} : (v: T, id: (t: T) => T) => T
|
||||
>Zet.prototype.add : any
|
||||
>Zet.prototype : any
|
||||
>Zet : typeof Zet
|
||||
>prototype : any
|
||||
>add : any
|
||||
>function(v, id) { this.u = v || this.t return id(this.u)} : (v: T, id: (t: T) => T) => T
|
||||
>v : T
|
||||
>id : (t: T) => T
|
||||
|
||||
this.u = v || this.t
|
||||
>this.u = v || this.t : T
|
||||
>this.u : T
|
||||
>this : Zet
|
||||
>u : T
|
||||
>v || this.t : T
|
||||
>v : T
|
||||
>this.t : T
|
||||
>this : Zet
|
||||
>t : T
|
||||
|
||||
return id(this.u)
|
||||
>id(this.u) : T
|
||||
>id : (t: T) => T
|
||||
>this.u : T
|
||||
>this : Zet
|
||||
>u : T
|
||||
}
|
||||
var z = new Zet(1)
|
||||
>z : typeof Zet
|
||||
>new Zet(1) : typeof Zet
|
||||
>Zet : typeof Zet
|
||||
>1 : 1
|
||||
|
||||
z.t = 2
|
||||
>z.t = 2 : 2
|
||||
>z.t : number
|
||||
>z : typeof Zet
|
||||
>t : number
|
||||
>2 : 2
|
||||
|
||||
z.u = false
|
||||
>z.u = false : false
|
||||
>z.u : number
|
||||
>z : typeof Zet
|
||||
>u : number
|
||||
>false : false
|
||||
|
||||
29
tests/cases/conformance/jsdoc/jsdocTemplateClass.ts
Normal file
29
tests/cases/conformance/jsdoc/jsdocTemplateClass.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noEmit: true
|
||||
// @Filename: templateTagOnClasses.js
|
||||
|
||||
/**
|
||||
* @template {T}
|
||||
* @typedef {(t: T) => T} Id
|
||||
*/
|
||||
class Foo {
|
||||
/** @typedef {(t: T) => T} Id2 */
|
||||
/** @param {T} x */
|
||||
constructor (x) {
|
||||
this.a = x
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {T} x
|
||||
* @param {Id} y
|
||||
* @param {Id2} alpha
|
||||
* @return {T}
|
||||
*/
|
||||
foo(x, y, alpha) {
|
||||
return alpha(y(x))
|
||||
}
|
||||
}
|
||||
var f = new Foo(1)
|
||||
var g = new Foo(false)
|
||||
f.a = g.a
|
||||
@@ -0,0 +1,26 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noEmit: true
|
||||
// @Filename: templateTagOnConstructorFunctions.js
|
||||
|
||||
/**
|
||||
* @template {T}
|
||||
* @typedef {(t: T) => T} Id
|
||||
* @param {T} t
|
||||
*/
|
||||
function Zet(t) {
|
||||
/** @type {T} */
|
||||
this.u
|
||||
this.t = t
|
||||
}
|
||||
/**
|
||||
* @param {T} v
|
||||
* @param {Id} id
|
||||
*/
|
||||
Zet.prototype.add = function(v, id) {
|
||||
this.u = v || this.t
|
||||
return id(this.u)
|
||||
}
|
||||
var z = new Zet(1)
|
||||
z.t = 2
|
||||
z.u = false
|
||||
@@ -3,15 +3,14 @@
|
||||
// @allowJs: true
|
||||
// @Filename: /a.js
|
||||
|
||||
// TODO: https://github.com/Microsoft/TypeScript/issues/16411
|
||||
// Both uses of T should be referenced.
|
||||
|
||||
/////** @template [|{| "isWriteAccess": true, "isDefinition": true |}T|] */
|
||||
////class C {
|
||||
//// constructor() {
|
||||
//// /** @type {T} */
|
||||
//// /** @type {[|T|]} */
|
||||
//// this.x = null;
|
||||
//// }
|
||||
////}
|
||||
|
||||
verify.singleReferenceGroup("(type parameter) T in C");
|
||||
verify.singleReferenceGroup("(type parameter) T in C<T>", test.ranges());
|
||||
|
||||
Reference in New Issue
Block a user