mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-12 12:57:11 -06:00
Report circular JSDoc type references (#27404)
JSDoc types references can often be to values, which can often be circular in ways that types tied to declarations cannot. I decided to create a separate property on SymbolLinks rather than reusing declaredType, although I'm not sure that's strictly required.
This commit is contained in:
parent
6afa880aa3
commit
a4a5b3806e
@ -666,6 +666,7 @@ namespace ts {
|
||||
ResolvedReturnType,
|
||||
ImmediateBaseConstraint,
|
||||
EnumTagType,
|
||||
JSDocTypeReference,
|
||||
}
|
||||
|
||||
const enum CheckMode {
|
||||
@ -4503,6 +4504,8 @@ namespace ts {
|
||||
return !!(<Signature>target).resolvedReturnType;
|
||||
case TypeSystemPropertyName.ImmediateBaseConstraint:
|
||||
return !!(<Type>target).immediateBaseConstraint;
|
||||
case TypeSystemPropertyName.JSDocTypeReference:
|
||||
return !!getSymbolLinks(target as Symbol).resolvedJSDocType;
|
||||
}
|
||||
return Debug.assertNever(propertyName);
|
||||
}
|
||||
@ -8275,7 +8278,7 @@ namespace ts {
|
||||
return type;
|
||||
}
|
||||
|
||||
// JS are 'string' or 'number', not an enum type.
|
||||
// JS enums are 'string' or 'number', not an enum type.
|
||||
const enumTag = isInJSFile(node) && symbol.valueDeclaration && getJSDocEnumTag(symbol.valueDeclaration);
|
||||
if (enumTag) {
|
||||
const links = getNodeLinks(enumTag);
|
||||
@ -8318,12 +8321,21 @@ namespace ts {
|
||||
* the type of this reference is just the type of the value we resolved to.
|
||||
*/
|
||||
function getJSDocTypeReference(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[] | undefined): Type | undefined {
|
||||
if (!pushTypeResolution(symbol, TypeSystemPropertyName.JSDocTypeReference)) {
|
||||
return errorType;
|
||||
}
|
||||
const assignedType = getAssignedClassType(symbol);
|
||||
const valueType = getTypeOfSymbol(symbol);
|
||||
const referenceType = valueType.symbol && valueType.symbol !== symbol && !isInferredClassType(valueType) && getTypeReferenceTypeWorker(node, valueType.symbol, typeArguments);
|
||||
if (!popTypeResolution()) {
|
||||
getSymbolLinks(symbol).resolvedJSDocType = errorType;
|
||||
error(node, Diagnostics.JSDoc_type_0_circularly_references_itself, symbolToString(symbol));
|
||||
return errorType;
|
||||
}
|
||||
if (referenceType || assignedType) {
|
||||
// TODO: GH#18217 (should the `|| assignedType` be at a lower precedence?)
|
||||
return (referenceType && assignedType ? getIntersectionType([assignedType, referenceType]) : referenceType || assignedType)!;
|
||||
const type = (referenceType && assignedType ? getIntersectionType([assignedType, referenceType]) : referenceType || assignedType)!;
|
||||
return getSymbolLinks(symbol).resolvedJSDocType = type;
|
||||
}
|
||||
}
|
||||
|
||||
@ -8460,7 +8472,7 @@ namespace ts {
|
||||
symbol = resolveTypeReferenceName(getTypeReferenceName(node), meaning);
|
||||
type = getTypeReferenceType(node, symbol);
|
||||
}
|
||||
// Cache both the resolved symbol and the resolved type. The resolved symbol is needed in when we check the
|
||||
// Cache both the resolved symbol and the resolved type. The resolved symbol is needed when we check the
|
||||
// type reference in checkTypeReferenceNode.
|
||||
links.resolvedSymbol = symbol;
|
||||
links.resolvedType = type;
|
||||
|
||||
@ -2116,6 +2116,10 @@
|
||||
"category": "Error",
|
||||
"code": 2586
|
||||
},
|
||||
"JSDoc type '{0}' circularly references itself.": {
|
||||
"category": "Error",
|
||||
"code": 2587
|
||||
},
|
||||
"JSX element attributes type '{0}' may not be a union type.": {
|
||||
"category": "Error",
|
||||
"code": 2600
|
||||
@ -4684,4 +4688,4 @@
|
||||
"category": "Message",
|
||||
"code": 95068
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3536,6 +3536,7 @@ namespace ts {
|
||||
type?: Type; // Type of value symbol
|
||||
uniqueESSymbolType?: Type; // UniqueESSymbol type for a symbol
|
||||
declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter
|
||||
resolvedJSDocType?: Type; // Resolved type of a JSDoc type reference
|
||||
typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic)
|
||||
outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type
|
||||
inferredClassType?: Type; // Type of an inferred ES5 class
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
tests/cases/conformance/jsdoc/bug27346.js(2,4): error TS8030: The type of a function declaration must match the function's signature.
|
||||
tests/cases/conformance/jsdoc/bug27346.js(2,11): error TS2587: JSDoc type 'MyClass' circularly references itself.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/bug27346.js (2 errors) ====
|
||||
/**
|
||||
* @type {MyClass}
|
||||
~~~~~~~~~~~~~~~
|
||||
!!! error TS8030: The type of a function declaration must match the function's signature.
|
||||
~~~~~~~
|
||||
!!! error TS2587: JSDoc type 'MyClass' circularly references itself.
|
||||
*/
|
||||
function MyClass() { }
|
||||
MyClass.prototype = {};
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
=== tests/cases/conformance/jsdoc/bug27346.js ===
|
||||
/**
|
||||
* @type {MyClass}
|
||||
*/
|
||||
function MyClass() { }
|
||||
>MyClass : Symbol(MyClass, Decl(bug27346.js, 0, 0), Decl(bug27346.js, 3, 22))
|
||||
|
||||
MyClass.prototype = {};
|
||||
>MyClass.prototype : Symbol(MyClass.prototype, Decl(bug27346.js, 3, 22))
|
||||
>MyClass : Symbol(MyClass, Decl(bug27346.js, 0, 0), Decl(bug27346.js, 3, 22))
|
||||
>prototype : Symbol(MyClass.prototype, Decl(bug27346.js, 3, 22))
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
=== tests/cases/conformance/jsdoc/bug27346.js ===
|
||||
/**
|
||||
* @type {MyClass}
|
||||
*/
|
||||
function MyClass() { }
|
||||
>MyClass : typeof MyClass
|
||||
|
||||
MyClass.prototype = {};
|
||||
>MyClass.prototype = {} : {}
|
||||
>MyClass.prototype : {}
|
||||
>MyClass : typeof MyClass
|
||||
>prototype : {}
|
||||
>{} : {}
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
// @allowJs: true
|
||||
// @noEmit: true
|
||||
// @checkJs: true
|
||||
// @Filename: bug27346.js
|
||||
/**
|
||||
* @type {MyClass}
|
||||
*/
|
||||
function MyClass() { }
|
||||
MyClass.prototype = {};
|
||||
Loading…
x
Reference in New Issue
Block a user