Repository: eslint-community/eslint-plugin-es-x
Pull request #101 (2023-11-21 14:59:38)

ignore `declare` statements in `no-class-fields`
The proposed change does nothing for vanilla JS, but it ignores `declare` statement in TS.

Related issue: #100 

ota-meshi: Could you please add tests?
bhsd-harry: > Could you please add tests?

Sorry, I am not sure what tests could be useful, so I only add a minimal set of tests to illustrate this patch.

Patch:
diff --git a/lib/rules/no-class-fields.js b/lib/rules/no-class-fields.js
index 9c42a91..42d06bf 100644
--- a/lib/rules/no-class-fields.js
+++ b/lib/rules/no-class-fields.js
@@ -62,6 +62,9 @@ module.exports = {
     create(context) {
         return {
             PropertyDefinition(node) {
+                if (node.declare || node.parent.parent.declare) {
+                    return
+                }
                 context.report({
                     node: node.key,
                     messageId: "forbidden",


Test patch:
diff --git a/tests/lib/rules/no-class-fields.js b/tests/lib/rules/no-class-fields.js
index a3266e6..d2b1a87 100644
--- a/tests/lib/rules/no-class-fields.js
+++ b/tests/lib/rules/no-class-fields.js
@@ -4,8 +4,10 @@
  */
 "use strict"
 
+const path = require("path")
 const RuleTester = require("../../tester")
 const rule = require("../../../lib/rules/no-class-fields.js")
+const ruleId = "no-class-fields"
 
 if (!RuleTester.isSupported(2022)) {
     //eslint-disable-next-line no-console
@@ -13,7 +15,7 @@ if (!RuleTester.isSupported(2022)) {
     return
 }
 
-new RuleTester().run("no-class-fields", rule, {
+new RuleTester().run(ruleId, rule, {
     valid: [
         "class A {}",
         "class A { foo() {} }",
@@ -221,3 +223,58 @@ new RuleTester().run("no-class-fields", rule, {
         },
     ],
 })
+
+// -----------------------------------------------------------------------------
+// TypeScript
+// -----------------------------------------------------------------------------
+const parser = require.resolve("@typescript-eslint/parser")
+const tsconfigRootDir = path.resolve(__dirname, "../../fixtures")
+const project = "tsconfig.json"
+const filename = path.join(tsconfigRootDir, "test.ts")
+
+new RuleTester({ parser, parserOptions: { tsconfigRootDir, project } }).run(
+    `${ruleId} TS Full Types`,
+    rule,
+    {
+        valid: [
+            {
+                filename,
+                code: "class A { declare foo: string }",
+            },
+            {
+                filename,
+                code: "class A { declare #foo: string }",
+            },
+            {
+                filename,
+                code: "declare class A { foo: string }",
+            },
+            {
+                filename,
+                code: "declare class A { #foo: string }",
+            },
+        ],
+        invalid: [
+            {
+                filename,
+                code: "class A { readonly foo = '' }",
+                errors: ["ES2022 field 'foo' is forbidden."],
+            },
+            {
+                filename,
+                code: "class A { foo: string }",
+                errors: ["ES2022 field 'foo' is forbidden."],
+            },
+            {
+                filename,
+                code: "class A { foo: string = '' }",
+                errors: ["ES2022 field 'foo' is forbidden."],
+            },
+            {
+                filename,
+                code: "class A { #foo: string }",
+                errors: ["ES2022 private field #foo is forbidden."],
+            },
+        ],
+    },
+)