From 6740253e50f6e04d5c87a9ddb236bbd66d3bdb0d Mon Sep 17 00:00:00 2001 From: Bharat Middha <5100938+bmiddha@users.noreply.github.com> Date: Wed, 19 Aug 2026 23:02:31 -0700 Subject: [PATCH] fix(eslint-plugin): recognize native privacy Treat PrivateIdentifier class keys like TypeScript private members so no-new-null does not report private API types. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8ebd5bf2-c44b-42d5-be25-e7936d4b0a14 --- .../native-private-null_2026-08-19-22-58-08.json | 9 +++++++++ eslint/eslint-plugin/src/no-new-null.ts | 9 +++++++-- eslint/eslint-plugin/src/test/no-new-null.test.ts | 11 +++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 common/changes/@rushstack/eslint-plugin/native-private-null_2026-08-19-22-58-08.json diff --git a/common/changes/@rushstack/eslint-plugin/native-private-null_2026-08-19-22-58-08.json b/common/changes/@rushstack/eslint-plugin/native-private-null_2026-08-19-22-58-08.json new file mode 100644 index 00000000000..f16f9e815e4 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin/native-private-null_2026-08-19-22-58-08.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "@rushstack/eslint-plugin", + "comment": "Fix no-new-null false positives for ECMAScript private class members.", + "type": "patch" + } + ] +} diff --git a/eslint/eslint-plugin/src/no-new-null.ts b/eslint/eslint-plugin/src/no-new-null.ts index 36d3e82db74..9c2774f6df1 100644 --- a/eslint/eslint-plugin/src/no-new-null.ts +++ b/eslint/eslint-plugin/src/no-new-null.ts @@ -9,6 +9,7 @@ type Options = []; interface IAccessible { accessibility?: TSESTree.Accessibility; + key?: TSESTree.Node; } const noNewNullRule: TSESLint.RuleModule = { @@ -37,11 +38,15 @@ const noNewNullRule: TSESLint.RuleModule = { create: (context: TSESLint.RuleContext) => { /** - * Returns true if the accessibility is not explicitly set to private or protected, e.g. class properties, methods. + * Returns true unless a class member uses protected, TypeScript-private, or ECMAScript-private syntax. */ function isPubliclyAccessible(node?: IAccessible): boolean { const accessibility: TSESTree.Accessibility | undefined = node?.accessibility; - return !(accessibility === 'private' || accessibility === 'protected'); + return ( + accessibility !== 'private' && + accessibility !== 'protected' && + node?.key?.type !== AST_NODE_TYPES.PrivateIdentifier + ); } /** diff --git a/eslint/eslint-plugin/src/test/no-new-null.test.ts b/eslint/eslint-plugin/src/test/no-new-null.test.ts index 7ae2fdf8045..87542636f2c 100644 --- a/eslint/eslint-plugin/src/test/no-new-null.test.ts +++ b/eslint/eslint-plugin/src/test/no-new-null.test.ts @@ -104,6 +104,17 @@ ruleTester.run('no-new-null', noNewNullRule, { ' }', '}' ].join('\n') + }, + { + code: [ + 'class NativePrivateNulls {', + ' #field: string | null;', + ' #propertyFunc: (value: string | null) => void;', + ' #method(value: string | null): string | null { return value; }', + ' get #value(): string | null { return this.#field; }', + ' set #value(value: string | null) { this.#field = value; }', + '}' + ].join('\n') } ] });