mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Readonly support for jsdoc (#35790)
* Add @readonly The rule for @readonly on this-assignments in the constructor is wrong. See failing tests. * In-progress Add ctor function test Add some notes and rename variable * Done except for cleanup and fix 1 bug * Fix last test and clean up
This commit is contained in:
+25
-17
@@ -11964,7 +11964,7 @@ namespace ts {
|
||||
if (prop) {
|
||||
if (accessExpression) {
|
||||
markPropertyAsReferenced(prop, accessExpression, /*isThisAccess*/ accessExpression.expression.kind === SyntaxKind.ThisKeyword);
|
||||
if (isAssignmentTarget(accessExpression) && (isReferenceToReadonlyEntity(accessExpression, prop) || isReferenceThroughNamespaceImport(accessExpression))) {
|
||||
if (isAssignmentToReadonlyEntity(accessExpression, prop, getAssignmentTargetKind(accessExpression))) {
|
||||
error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(prop));
|
||||
return undefined;
|
||||
}
|
||||
@@ -23046,11 +23046,9 @@ namespace ts {
|
||||
markPropertyAsReferenced(prop, node, left.kind === SyntaxKind.ThisKeyword);
|
||||
getNodeLinks(node).resolvedSymbol = prop;
|
||||
checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, apparentType, prop);
|
||||
if (assignmentKind) {
|
||||
if (isReferenceToReadonlyEntity(<Expression>node, prop) || isReferenceThroughNamespaceImport(<Expression>node)) {
|
||||
error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right));
|
||||
return errorType;
|
||||
}
|
||||
if (isAssignmentToReadonlyEntity(node as Expression, prop, assignmentKind)) {
|
||||
error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right));
|
||||
return errorType;
|
||||
}
|
||||
propType = getConstraintForLocation(getTypeOfSymbol(prop), node);
|
||||
}
|
||||
@@ -26332,29 +26330,39 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
function isReferenceToReadonlyEntity(expr: Expression, symbol: Symbol): boolean {
|
||||
function isAssignmentToReadonlyEntity(expr: Expression, symbol: Symbol, assignmentKind: AssignmentKind) {
|
||||
if (assignmentKind === AssignmentKind.None) {
|
||||
// no assigment means it doesn't matter whether the entity is readonly
|
||||
return false;
|
||||
}
|
||||
if (isReadonlySymbol(symbol)) {
|
||||
// Allow assignments to readonly properties within constructors of the same class declaration.
|
||||
if (symbol.flags & SymbolFlags.Property &&
|
||||
(expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) &&
|
||||
(expr as AccessExpression).expression.kind === SyntaxKind.ThisKeyword) {
|
||||
// Look for if this is the constructor for the class that `symbol` is a property of.
|
||||
const func = getContainingFunction(expr);
|
||||
if (!(func && func.kind === SyntaxKind.Constructor)) {
|
||||
const ctor = getContainingFunction(expr);
|
||||
if (!(ctor && ctor.kind === SyntaxKind.Constructor)) {
|
||||
return true;
|
||||
}
|
||||
// If func.parent is a class and symbol is a (readonly) property of that class, or
|
||||
// if func is a constructor and symbol is a (readonly) parameter property declared in it,
|
||||
// then symbol is writeable here.
|
||||
return !symbol.valueDeclaration || !(func.parent === symbol.valueDeclaration.parent || func === symbol.valueDeclaration.parent);
|
||||
if (symbol.valueDeclaration) {
|
||||
const isAssignmentDeclaration = isBinaryExpression(symbol.valueDeclaration);
|
||||
const isLocalPropertyDeclaration = ctor.parent === symbol.valueDeclaration.parent;
|
||||
const isLocalParameterProperty = ctor === symbol.valueDeclaration.parent;
|
||||
const isLocalThisPropertyAssignment = isAssignmentDeclaration && symbol.parent?.valueDeclaration === ctor.parent;
|
||||
const isLocalThisPropertyAssignmentConstructorFunction = isAssignmentDeclaration && symbol.parent?.valueDeclaration === ctor;
|
||||
const isWriteableSymbol =
|
||||
isLocalPropertyDeclaration
|
||||
|| isLocalParameterProperty
|
||||
|| isLocalThisPropertyAssignment
|
||||
|| isLocalThisPropertyAssignmentConstructorFunction;
|
||||
return !isWriteableSymbol;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isReferenceThroughNamespaceImport(expr: Expression): boolean {
|
||||
if (expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) {
|
||||
// references through namespace import should be readonly
|
||||
const node = skipParentheses((expr as AccessExpression).expression);
|
||||
if (node.kind === SyntaxKind.Identifier) {
|
||||
const symbol = getNodeLinks(node).resolvedSymbol!;
|
||||
|
||||
@@ -509,6 +509,7 @@ namespace ts {
|
||||
case SyntaxKind.JSDocPublicTag:
|
||||
case SyntaxKind.JSDocPrivateTag:
|
||||
case SyntaxKind.JSDocProtectedTag:
|
||||
case SyntaxKind.JSDocReadonlyTag:
|
||||
return visitNode(cbNode, (node as JSDocTag).tagName);
|
||||
case SyntaxKind.PartiallyEmittedExpression:
|
||||
return visitNode(cbNode, (<PartiallyEmittedExpression>node).expression);
|
||||
@@ -6845,6 +6846,9 @@ namespace ts {
|
||||
case "protected":
|
||||
tag = parseSimpleTag(start, SyntaxKind.JSDocProtectedTag, tagName);
|
||||
break;
|
||||
case "readonly":
|
||||
tag = parseSimpleTag(start, SyntaxKind.JSDocReadonlyTag, tagName);
|
||||
break;
|
||||
case "this":
|
||||
tag = parseThisTag(start, tagName);
|
||||
break;
|
||||
|
||||
@@ -471,6 +471,7 @@ namespace ts {
|
||||
JSDocPublicTag,
|
||||
JSDocPrivateTag,
|
||||
JSDocProtectedTag,
|
||||
JSDocReadonlyTag,
|
||||
JSDocCallbackTag,
|
||||
JSDocEnumTag,
|
||||
JSDocParameterTag,
|
||||
@@ -2632,6 +2633,10 @@ namespace ts {
|
||||
kind: SyntaxKind.JSDocProtectedTag;
|
||||
}
|
||||
|
||||
export interface JSDocReadonlyTag extends JSDocTag {
|
||||
kind: SyntaxKind.JSDocReadonlyTag;
|
||||
}
|
||||
|
||||
export interface JSDocEnumTag extends JSDocTag, Declaration {
|
||||
parent: JSDoc;
|
||||
kind: SyntaxKind.JSDocEnumTag;
|
||||
|
||||
@@ -4130,7 +4130,8 @@ namespace ts {
|
||||
// or when !(node.flags & NodeFlags.Synthesized) && node.kind !== SyntaxKind.SourceFile)
|
||||
const tags = (getJSDocPublicTag(node) ? ModifierFlags.Public : ModifierFlags.None)
|
||||
| (getJSDocPrivateTag(node) ? ModifierFlags.Private : ModifierFlags.None)
|
||||
| (getJSDocProtectedTag(node) ? ModifierFlags.Protected : ModifierFlags.None);
|
||||
| (getJSDocProtectedTag(node) ? ModifierFlags.Protected : ModifierFlags.None)
|
||||
| (getJSDocReadonlyTag(node) ? ModifierFlags.Readonly : ModifierFlags.None);
|
||||
flags |= tags;
|
||||
}
|
||||
|
||||
|
||||
@@ -688,6 +688,11 @@ namespace ts {
|
||||
return getFirstJSDocTag(node, isJSDocProtectedTag);
|
||||
}
|
||||
|
||||
/** Gets the JSDoc protected tag for the node if present */
|
||||
export function getJSDocReadonlyTag(node: Node): JSDocReadonlyTag | undefined {
|
||||
return getFirstJSDocTag(node, isJSDocReadonlyTag);
|
||||
}
|
||||
|
||||
/** Gets the JSDoc enum tag for the node if present */
|
||||
export function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined {
|
||||
return getFirstJSDocTag(node, isJSDocEnumTag);
|
||||
@@ -1574,6 +1579,10 @@ namespace ts {
|
||||
return node.kind === SyntaxKind.JSDocProtectedTag;
|
||||
}
|
||||
|
||||
export function isJSDocReadonlyTag(node: Node): node is JSDocReadonlyTag {
|
||||
return node.kind === SyntaxKind.JSDocReadonlyTag;
|
||||
}
|
||||
|
||||
export function isJSDocEnumTag(node: Node): node is JSDocEnumTag {
|
||||
return node.kind === SyntaxKind.JSDocEnumTag;
|
||||
}
|
||||
|
||||
+26
-19
@@ -386,23 +386,24 @@ declare namespace ts {
|
||||
JSDocPublicTag = 308,
|
||||
JSDocPrivateTag = 309,
|
||||
JSDocProtectedTag = 310,
|
||||
JSDocCallbackTag = 311,
|
||||
JSDocEnumTag = 312,
|
||||
JSDocParameterTag = 313,
|
||||
JSDocReturnTag = 314,
|
||||
JSDocThisTag = 315,
|
||||
JSDocTypeTag = 316,
|
||||
JSDocTemplateTag = 317,
|
||||
JSDocTypedefTag = 318,
|
||||
JSDocPropertyTag = 319,
|
||||
SyntaxList = 320,
|
||||
NotEmittedStatement = 321,
|
||||
PartiallyEmittedExpression = 322,
|
||||
CommaListExpression = 323,
|
||||
MergeDeclarationMarker = 324,
|
||||
EndOfDeclarationMarker = 325,
|
||||
SyntheticReferenceExpression = 326,
|
||||
Count = 327,
|
||||
JSDocReadonlyTag = 311,
|
||||
JSDocCallbackTag = 312,
|
||||
JSDocEnumTag = 313,
|
||||
JSDocParameterTag = 314,
|
||||
JSDocReturnTag = 315,
|
||||
JSDocThisTag = 316,
|
||||
JSDocTypeTag = 317,
|
||||
JSDocTemplateTag = 318,
|
||||
JSDocTypedefTag = 319,
|
||||
JSDocPropertyTag = 320,
|
||||
SyntaxList = 321,
|
||||
NotEmittedStatement = 322,
|
||||
PartiallyEmittedExpression = 323,
|
||||
CommaListExpression = 324,
|
||||
MergeDeclarationMarker = 325,
|
||||
EndOfDeclarationMarker = 326,
|
||||
SyntheticReferenceExpression = 327,
|
||||
Count = 328,
|
||||
FirstAssignment = 62,
|
||||
LastAssignment = 74,
|
||||
FirstCompoundAssignment = 63,
|
||||
@@ -431,9 +432,9 @@ declare namespace ts {
|
||||
LastStatement = 240,
|
||||
FirstNode = 152,
|
||||
FirstJSDocNode = 292,
|
||||
LastJSDocNode = 319,
|
||||
LastJSDocNode = 320,
|
||||
FirstJSDocTagNode = 304,
|
||||
LastJSDocTagNode = 319,
|
||||
LastJSDocTagNode = 320,
|
||||
}
|
||||
export enum NodeFlags {
|
||||
None = 0,
|
||||
@@ -1632,6 +1633,9 @@ declare namespace ts {
|
||||
export interface JSDocProtectedTag extends JSDocTag {
|
||||
kind: SyntaxKind.JSDocProtectedTag;
|
||||
}
|
||||
export interface JSDocReadonlyTag extends JSDocTag {
|
||||
kind: SyntaxKind.JSDocReadonlyTag;
|
||||
}
|
||||
export interface JSDocEnumTag extends JSDocTag, Declaration {
|
||||
parent: JSDoc;
|
||||
kind: SyntaxKind.JSDocEnumTag;
|
||||
@@ -3472,6 +3476,8 @@ declare namespace ts {
|
||||
function getJSDocPrivateTag(node: Node): JSDocPrivateTag | undefined;
|
||||
/** Gets the JSDoc protected tag for the node if present */
|
||||
function getJSDocProtectedTag(node: Node): JSDocProtectedTag | undefined;
|
||||
/** Gets the JSDoc protected tag for the node if present */
|
||||
function getJSDocReadonlyTag(node: Node): JSDocReadonlyTag | undefined;
|
||||
/** Gets the JSDoc enum tag for the node if present */
|
||||
function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined;
|
||||
/** Gets the JSDoc this tag for the node if present */
|
||||
@@ -3679,6 +3685,7 @@ declare namespace ts {
|
||||
function isJSDocPublicTag(node: Node): node is JSDocPublicTag;
|
||||
function isJSDocPrivateTag(node: Node): node is JSDocPrivateTag;
|
||||
function isJSDocProtectedTag(node: Node): node is JSDocProtectedTag;
|
||||
function isJSDocReadonlyTag(node: Node): node is JSDocReadonlyTag;
|
||||
function isJSDocEnumTag(node: Node): node is JSDocEnumTag;
|
||||
function isJSDocThisTag(node: Node): node is JSDocThisTag;
|
||||
function isJSDocParameterTag(node: Node): node is JSDocParameterTag;
|
||||
|
||||
+26
-19
@@ -386,23 +386,24 @@ declare namespace ts {
|
||||
JSDocPublicTag = 308,
|
||||
JSDocPrivateTag = 309,
|
||||
JSDocProtectedTag = 310,
|
||||
JSDocCallbackTag = 311,
|
||||
JSDocEnumTag = 312,
|
||||
JSDocParameterTag = 313,
|
||||
JSDocReturnTag = 314,
|
||||
JSDocThisTag = 315,
|
||||
JSDocTypeTag = 316,
|
||||
JSDocTemplateTag = 317,
|
||||
JSDocTypedefTag = 318,
|
||||
JSDocPropertyTag = 319,
|
||||
SyntaxList = 320,
|
||||
NotEmittedStatement = 321,
|
||||
PartiallyEmittedExpression = 322,
|
||||
CommaListExpression = 323,
|
||||
MergeDeclarationMarker = 324,
|
||||
EndOfDeclarationMarker = 325,
|
||||
SyntheticReferenceExpression = 326,
|
||||
Count = 327,
|
||||
JSDocReadonlyTag = 311,
|
||||
JSDocCallbackTag = 312,
|
||||
JSDocEnumTag = 313,
|
||||
JSDocParameterTag = 314,
|
||||
JSDocReturnTag = 315,
|
||||
JSDocThisTag = 316,
|
||||
JSDocTypeTag = 317,
|
||||
JSDocTemplateTag = 318,
|
||||
JSDocTypedefTag = 319,
|
||||
JSDocPropertyTag = 320,
|
||||
SyntaxList = 321,
|
||||
NotEmittedStatement = 322,
|
||||
PartiallyEmittedExpression = 323,
|
||||
CommaListExpression = 324,
|
||||
MergeDeclarationMarker = 325,
|
||||
EndOfDeclarationMarker = 326,
|
||||
SyntheticReferenceExpression = 327,
|
||||
Count = 328,
|
||||
FirstAssignment = 62,
|
||||
LastAssignment = 74,
|
||||
FirstCompoundAssignment = 63,
|
||||
@@ -431,9 +432,9 @@ declare namespace ts {
|
||||
LastStatement = 240,
|
||||
FirstNode = 152,
|
||||
FirstJSDocNode = 292,
|
||||
LastJSDocNode = 319,
|
||||
LastJSDocNode = 320,
|
||||
FirstJSDocTagNode = 304,
|
||||
LastJSDocTagNode = 319,
|
||||
LastJSDocTagNode = 320,
|
||||
}
|
||||
export enum NodeFlags {
|
||||
None = 0,
|
||||
@@ -1632,6 +1633,9 @@ declare namespace ts {
|
||||
export interface JSDocProtectedTag extends JSDocTag {
|
||||
kind: SyntaxKind.JSDocProtectedTag;
|
||||
}
|
||||
export interface JSDocReadonlyTag extends JSDocTag {
|
||||
kind: SyntaxKind.JSDocReadonlyTag;
|
||||
}
|
||||
export interface JSDocEnumTag extends JSDocTag, Declaration {
|
||||
parent: JSDoc;
|
||||
kind: SyntaxKind.JSDocEnumTag;
|
||||
@@ -3472,6 +3476,8 @@ declare namespace ts {
|
||||
function getJSDocPrivateTag(node: Node): JSDocPrivateTag | undefined;
|
||||
/** Gets the JSDoc protected tag for the node if present */
|
||||
function getJSDocProtectedTag(node: Node): JSDocProtectedTag | undefined;
|
||||
/** Gets the JSDoc protected tag for the node if present */
|
||||
function getJSDocReadonlyTag(node: Node): JSDocReadonlyTag | undefined;
|
||||
/** Gets the JSDoc enum tag for the node if present */
|
||||
function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined;
|
||||
/** Gets the JSDoc this tag for the node if present */
|
||||
@@ -3679,6 +3685,7 @@ declare namespace ts {
|
||||
function isJSDocPublicTag(node: Node): node is JSDocPublicTag;
|
||||
function isJSDocPrivateTag(node: Node): node is JSDocPrivateTag;
|
||||
function isJSDocProtectedTag(node: Node): node is JSDocProtectedTag;
|
||||
function isJSDocReadonlyTag(node: Node): node is JSDocReadonlyTag;
|
||||
function isJSDocEnumTag(node: Node): node is JSDocEnumTag;
|
||||
function isJSDocThisTag(node: Node): node is JSDocThisTag;
|
||||
function isJSDocParameterTag(node: Node): node is JSDocParameterTag;
|
||||
|
||||
@@ -477,7 +477,7 @@ export class E<T, U> {
|
||||
* @type {string}
|
||||
* @readonly
|
||||
*/
|
||||
static staticReadonlyField: string;
|
||||
static readonly staticReadonlyField: string;
|
||||
static staticInitializedField: number;
|
||||
/**
|
||||
* @param {string} _p
|
||||
@@ -508,7 +508,7 @@ export class E<T, U> {
|
||||
* @type {T & U}
|
||||
* @readonly
|
||||
*/
|
||||
readonlyField: T & U;
|
||||
readonly readonlyField: T & U;
|
||||
initializedField: number;
|
||||
/**
|
||||
* @param {U} _p
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
tests/cases/conformance/jsdoc/jsdocReadonly.js(23,3): error TS2540: Cannot assign to 'y' because it is a read-only property.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/jsdocReadonly.js (1 errors) ====
|
||||
class LOL {
|
||||
/**
|
||||
* @readonly
|
||||
* @private
|
||||
* @type {number}
|
||||
* Order rules do not apply to JSDoc
|
||||
*/
|
||||
x = 1
|
||||
/** @readonly */
|
||||
y = 2
|
||||
/** @readonly Definitely not here */
|
||||
static z = 3
|
||||
/** @readonly This is OK too */
|
||||
constructor() {
|
||||
/** ok */
|
||||
this.y = 2
|
||||
/** @readonly ok */
|
||||
this.ka = 2
|
||||
}
|
||||
}
|
||||
|
||||
var l = new LOL()
|
||||
l.y = 12
|
||||
~
|
||||
!!! error TS2540: Cannot assign to 'y' because it is a read-only property.
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
=== tests/cases/conformance/jsdoc/jsdocReadonly.js ===
|
||||
class LOL {
|
||||
>LOL : Symbol(LOL, Decl(jsdocReadonly.js, 0, 0))
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @private
|
||||
* @type {number}
|
||||
* Order rules do not apply to JSDoc
|
||||
*/
|
||||
x = 1
|
||||
>x : Symbol(LOL.x, Decl(jsdocReadonly.js, 0, 11))
|
||||
|
||||
/** @readonly */
|
||||
y = 2
|
||||
>y : Symbol(LOL.y, Decl(jsdocReadonly.js, 7, 9))
|
||||
|
||||
/** @readonly Definitely not here */
|
||||
static z = 3
|
||||
>z : Symbol(LOL.z, Decl(jsdocReadonly.js, 9, 9))
|
||||
|
||||
/** @readonly This is OK too */
|
||||
constructor() {
|
||||
/** ok */
|
||||
this.y = 2
|
||||
>this.y : Symbol(LOL.y, Decl(jsdocReadonly.js, 7, 9))
|
||||
>this : Symbol(LOL, Decl(jsdocReadonly.js, 0, 0))
|
||||
>y : Symbol(LOL.y, Decl(jsdocReadonly.js, 7, 9))
|
||||
|
||||
/** @readonly ok */
|
||||
this.ka = 2
|
||||
>this.ka : Symbol(LOL.ka, Decl(jsdocReadonly.js, 15, 18))
|
||||
>this : Symbol(LOL, Decl(jsdocReadonly.js, 0, 0))
|
||||
>ka : Symbol(LOL.ka, Decl(jsdocReadonly.js, 15, 18))
|
||||
}
|
||||
}
|
||||
|
||||
var l = new LOL()
|
||||
>l : Symbol(l, Decl(jsdocReadonly.js, 21, 3), Decl(jsdocReadonly.js, 21, 17))
|
||||
>LOL : Symbol(LOL, Decl(jsdocReadonly.js, 0, 0))
|
||||
|
||||
l.y = 12
|
||||
>l.y : Symbol(LOL.y, Decl(jsdocReadonly.js, 7, 9))
|
||||
>l : Symbol(l, Decl(jsdocReadonly.js, 21, 3), Decl(jsdocReadonly.js, 21, 17))
|
||||
>y : Symbol(LOL.y, Decl(jsdocReadonly.js, 7, 9))
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
=== tests/cases/conformance/jsdoc/jsdocReadonly.js ===
|
||||
class LOL {
|
||||
>LOL : LOL
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @private
|
||||
* @type {number}
|
||||
* Order rules do not apply to JSDoc
|
||||
*/
|
||||
x = 1
|
||||
>x : number
|
||||
>1 : 1
|
||||
|
||||
/** @readonly */
|
||||
y = 2
|
||||
>y : 2
|
||||
>2 : 2
|
||||
|
||||
/** @readonly Definitely not here */
|
||||
static z = 3
|
||||
>z : 3
|
||||
>3 : 3
|
||||
|
||||
/** @readonly This is OK too */
|
||||
constructor() {
|
||||
/** ok */
|
||||
this.y = 2
|
||||
>this.y = 2 : 2
|
||||
>this.y : 2
|
||||
>this : this
|
||||
>y : 2
|
||||
>2 : 2
|
||||
|
||||
/** @readonly ok */
|
||||
this.ka = 2
|
||||
>this.ka = 2 : 2
|
||||
>this.ka : number
|
||||
>this : this
|
||||
>ka : number
|
||||
>2 : 2
|
||||
}
|
||||
}
|
||||
|
||||
var l = new LOL()
|
||||
>l : LOL
|
||||
>new LOL() : LOL
|
||||
>LOL : typeof LOL
|
||||
|
||||
l.y = 12
|
||||
>l.y = 12 : 12
|
||||
>l.y : any
|
||||
>l : LOL
|
||||
>y : any
|
||||
>12 : 12
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
//// [jsdocReadonlyDeclarations.js]
|
||||
class C {
|
||||
/** @readonly */
|
||||
x = 6
|
||||
/** @readonly */
|
||||
constructor(n) {
|
||||
this.x = n
|
||||
/**
|
||||
* @readonly
|
||||
* @type {number}
|
||||
*/
|
||||
this.y = n
|
||||
}
|
||||
}
|
||||
new C().x
|
||||
|
||||
function F() {
|
||||
/** @readonly */
|
||||
this.z = 1
|
||||
}
|
||||
|
||||
|
||||
//// [foo.js]
|
||||
class C {
|
||||
/** @readonly */
|
||||
constructor(n) {
|
||||
/** @readonly */
|
||||
this.x = 6;
|
||||
this.x = n;
|
||||
/**
|
||||
* @readonly
|
||||
* @type {number}
|
||||
*/
|
||||
this.y = n;
|
||||
}
|
||||
}
|
||||
new C().x;
|
||||
function F() {
|
||||
/** @readonly */
|
||||
this.z = 1;
|
||||
}
|
||||
|
||||
|
||||
//// [foo.d.ts]
|
||||
declare function F(): void;
|
||||
declare class F {
|
||||
/** @readonly */
|
||||
readonly z: number;
|
||||
}
|
||||
declare class C {
|
||||
/** @readonly */
|
||||
constructor(n: any);
|
||||
/** @readonly */
|
||||
readonly x: 6;
|
||||
/**
|
||||
* @readonly
|
||||
* @type {number}
|
||||
*/
|
||||
readonly y: number;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
=== tests/cases/conformance/jsdoc/jsdocReadonlyDeclarations.js ===
|
||||
class C {
|
||||
>C : Symbol(C, Decl(jsdocReadonlyDeclarations.js, 0, 0))
|
||||
|
||||
/** @readonly */
|
||||
x = 6
|
||||
>x : Symbol(C.x, Decl(jsdocReadonlyDeclarations.js, 0, 9))
|
||||
|
||||
/** @readonly */
|
||||
constructor(n) {
|
||||
>n : Symbol(n, Decl(jsdocReadonlyDeclarations.js, 4, 16))
|
||||
|
||||
this.x = n
|
||||
>this.x : Symbol(C.x, Decl(jsdocReadonlyDeclarations.js, 0, 9))
|
||||
>this : Symbol(C, Decl(jsdocReadonlyDeclarations.js, 0, 0))
|
||||
>x : Symbol(C.x, Decl(jsdocReadonlyDeclarations.js, 0, 9))
|
||||
>n : Symbol(n, Decl(jsdocReadonlyDeclarations.js, 4, 16))
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @type {number}
|
||||
*/
|
||||
this.y = n
|
||||
>this.y : Symbol(C.y, Decl(jsdocReadonlyDeclarations.js, 5, 18))
|
||||
>this : Symbol(C, Decl(jsdocReadonlyDeclarations.js, 0, 0))
|
||||
>y : Symbol(C.y, Decl(jsdocReadonlyDeclarations.js, 5, 18))
|
||||
>n : Symbol(n, Decl(jsdocReadonlyDeclarations.js, 4, 16))
|
||||
}
|
||||
}
|
||||
new C().x
|
||||
>new C().x : Symbol(C.x, Decl(jsdocReadonlyDeclarations.js, 0, 9))
|
||||
>C : Symbol(C, Decl(jsdocReadonlyDeclarations.js, 0, 0))
|
||||
>x : Symbol(C.x, Decl(jsdocReadonlyDeclarations.js, 0, 9))
|
||||
|
||||
function F() {
|
||||
>F : Symbol(F, Decl(jsdocReadonlyDeclarations.js, 13, 9))
|
||||
|
||||
/** @readonly */
|
||||
this.z = 1
|
||||
>z : Symbol(F.z, Decl(jsdocReadonlyDeclarations.js, 15, 14))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
=== tests/cases/conformance/jsdoc/jsdocReadonlyDeclarations.js ===
|
||||
class C {
|
||||
>C : C
|
||||
|
||||
/** @readonly */
|
||||
x = 6
|
||||
>x : 6
|
||||
>6 : 6
|
||||
|
||||
/** @readonly */
|
||||
constructor(n) {
|
||||
>n : any
|
||||
|
||||
this.x = n
|
||||
>this.x = n : any
|
||||
>this.x : 6
|
||||
>this : this
|
||||
>x : 6
|
||||
>n : any
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @type {number}
|
||||
*/
|
||||
this.y = n
|
||||
>this.y = n : any
|
||||
>this.y : number
|
||||
>this : this
|
||||
>y : number
|
||||
>n : any
|
||||
}
|
||||
}
|
||||
new C().x
|
||||
>new C().x : 6
|
||||
>new C() : C
|
||||
>C : typeof C
|
||||
>x : 6
|
||||
|
||||
function F() {
|
||||
>F : typeof F
|
||||
|
||||
/** @readonly */
|
||||
this.z = 1
|
||||
>this.z = 1 : 1
|
||||
>this.z : any
|
||||
>this : any
|
||||
>z : any
|
||||
>1 : 1
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @target: esnext
|
||||
// @noEmit: true
|
||||
// @Filename: jsdocReadonly.js
|
||||
|
||||
class LOL {
|
||||
/**
|
||||
* @readonly
|
||||
* @private
|
||||
* @type {number}
|
||||
* Order rules do not apply to JSDoc
|
||||
*/
|
||||
x = 1
|
||||
/** @readonly */
|
||||
y = 2
|
||||
/** @readonly Definitely not here */
|
||||
static z = 3
|
||||
/** @readonly This is OK too */
|
||||
constructor() {
|
||||
/** ok */
|
||||
this.y = 2
|
||||
/** @readonly ok */
|
||||
this.ka = 2
|
||||
}
|
||||
}
|
||||
|
||||
var l = new LOL()
|
||||
l.y = 12
|
||||
@@ -0,0 +1,25 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @target: esnext
|
||||
// @out: foo.js
|
||||
// @declaration: true
|
||||
// @Filename: jsdocReadonlyDeclarations.js
|
||||
class C {
|
||||
/** @readonly */
|
||||
x = 6
|
||||
/** @readonly */
|
||||
constructor(n) {
|
||||
this.x = n
|
||||
/**
|
||||
* @readonly
|
||||
* @type {number}
|
||||
*/
|
||||
this.y = n
|
||||
}
|
||||
}
|
||||
new C().x
|
||||
|
||||
function F() {
|
||||
/** @readonly */
|
||||
this.z = 1
|
||||
}
|
||||
Reference in New Issue
Block a user