From 4e2694b6b7436eae2d133d6fb714338b7fe91fe2 Mon Sep 17 00:00:00 2001
From: Olivier Zalmanski <88216225+OlivierZal@users.noreply.github.com>
Date: Thu, 27 Mar 2025 14:08:01 +0100
Subject: [PATCH 1/3] feat(eslint-plugin): [prefer-nullish-coalescing] create
`ignoreIfStatements` option
---
.../docs/rules/prefer-nullish-coalescing.mdx | 49 +++++++++++++++
.../src/rules/prefer-nullish-coalescing.ts | 10 +++-
.../prefer-nullish-coalescing.shot | 60 ++++++++++++++++---
.../rules/prefer-nullish-coalescing.test.ts | 24 ++++++++
4 files changed, 135 insertions(+), 8 deletions(-)
diff --git a/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.mdx b/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.mdx
index 904c7f40b7fe..90c6094c38bb 100644
--- a/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.mdx
+++ b/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.mdx
@@ -118,6 +118,55 @@ c ?? 'a string';
+### `ignoreIfStatements`
+
+{/* insert option description */}
+
+Examples of code for this rule with `{ ignoreIfStatements: false }`:
+
+
+
+
+```ts option='{ "ignoreIfStatements": false }'
+declare let foo: { a: string } | null;
+declare function makeFoo(): { a: string };
+
+function lazyInitializeFoo() {
+ if (!foo) {
+ foo = makeFoo();
+ }
+}
+
+declare let bar: { a: string } | null;
+declare function makeBar(): { a: string };
+
+function lazyInitializeBar() {
+ if (!bar) bar = makeBar();
+}
+```
+
+
+
+
+```ts option='{ "ignoreIfStatements": false }'
+declare let foo: { a: string } | null;
+declare function makeFoo(): { a: string };
+
+function lazyInitializeFoo() {
+ foo ??= makeFoo();
+}
+
+declare let bar: { a: string } | null;
+declare function makeBar(): { a: string };
+
+function lazyInitializeBar() {
+ bar ??= makeBar();
+}
+```
+
+
+
+
### `ignoreConditionalTests`
{/* insert option description */}
diff --git a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts
index 8f49f74089a8..940566a801a8 100644
--- a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts
+++ b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts
@@ -50,6 +50,7 @@ export type Options = [
}
| true;
ignoreTernaryTests?: boolean;
+ ignoreIfStatements?: boolean;
},
];
@@ -145,6 +146,11 @@ export default createRule({
description:
'Whether to ignore any ternary expressions that could be simplified by using the nullish coalescing operator.',
},
+ ignoreIfStatements: {
+ type: 'boolean',
+ description:
+ 'Whether to ignore any if statements that could be simplified by using the nullish coalescing operator.',
+ },
},
},
],
@@ -162,6 +168,7 @@ export default createRule({
string: false,
},
ignoreTernaryTests: false,
+ ignoreIfStatements: false,
},
],
create(
@@ -174,6 +181,7 @@ export default createRule({
ignoreMixedLogicalExpressions,
ignorePrimitives,
ignoreTernaryTests,
+ ignoreIfStatements,
},
],
) {
@@ -516,7 +524,7 @@ export default createRule({
}
},
IfStatement(node: TSESTree.IfStatement): void {
- if (node.alternate != null) {
+ if (ignoreIfStatements || node.alternate != null) {
return;
}
diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/prefer-nullish-coalescing.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/prefer-nullish-coalescing.shot
index 46ff002cd623..33092a4f6852 100644
--- a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/prefer-nullish-coalescing.shot
+++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/prefer-nullish-coalescing.shot
@@ -102,6 +102,52 @@ c ?? 'a string';
exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 5`] = `
"Incorrect
+Options: { "ignoreIfStatements": false }
+
+declare let foo: { a: string } | null;
+declare function makeFoo(): { a: string };
+
+function lazyInitializeFoo() {
+ if (!foo) {
+ ~~~~~~~~~~~ Prefer using nullish coalescing operator (\`??=\`) instead of an assignment expression, as it is simpler to read.
+ foo = makeFoo();
+~~~~~~~~~~~~~~~~~~~~
+ }
+~~~
+}
+
+declare let bar: { a: string } | null;
+declare function makeBar(): { a: string };
+
+function lazyInitializeBar() {
+ if (!bar) bar = makeBar();
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~ Prefer using nullish coalescing operator (\`??=\`) instead of an assignment expression, as it is simpler to read.
+}
+"
+`;
+
+exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 6`] = `
+"Correct
+Options: { "ignoreIfStatements": false }
+
+declare let foo: { a: string } | null;
+declare function makeFoo(): { a: string };
+
+function lazyInitializeFoo() {
+ foo ??= makeFoo();
+}
+
+declare let bar: { a: string } | null;
+declare function makeBar(): { a: string };
+
+function lazyInitializeBar() {
+ bar ??= makeBar();
+}
+"
+`;
+
+exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 7`] = `
+"Incorrect
Options: { "ignoreConditionalTests": false }
declare let a: string | null;
@@ -126,7 +172,7 @@ a || b ? true : false;
"
`;
-exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 6`] = `
+exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 8`] = `
"Correct
Options: { "ignoreConditionalTests": false }
@@ -145,7 +191,7 @@ for (let i = 0; a ?? b; i += 1) {}
"
`;
-exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 7`] = `
+exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 9`] = `
"Incorrect
Options: { "ignoreMixedLogicalExpressions": false }
@@ -169,7 +215,7 @@ a || (b && c && d);
"
`;
-exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 8`] = `
+exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 10`] = `
"Correct
Options: { "ignoreMixedLogicalExpressions": false }
@@ -186,7 +232,7 @@ a ?? (b && c && d);
"
`;
-exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 9`] = `
+exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 11`] = `
"Incorrect
Options: { "ignorePrimitives": { "string": false } }
@@ -197,7 +243,7 @@ foo || 'a string';
"
`;
-exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 10`] = `
+exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 12`] = `
"Correct
Options: { "ignorePrimitives": { "string": false } }
@@ -207,7 +253,7 @@ foo ?? 'a string';
"
`;
-exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 11`] = `
+exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 13`] = `
"Incorrect
Options: { "ignoreBooleanCoercion": false }
@@ -219,7 +265,7 @@ const x = Boolean(a || b);
"
`;
-exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 12`] = `
+exports[`Validating rule docs prefer-nullish-coalescing.mdx code examples ESLint output 14`] = `
"Correct
Options: { "ignoreBooleanCoercion": false }
diff --git a/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts b/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts
index b17d4753f074..0926a839ee38 100644
--- a/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts
+++ b/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts
@@ -518,6 +518,30 @@ x?.a ? y?.a : 'foo'
code,
options: [{ ignoreTernaryTests: false }] as const,
})),
+ {
+ code: `
+declare let foo: { a: string } | null;
+declare function makeFoo(): { a: string };
+
+function lazyInitialize() {
+ if (!foo) {
+ foo = makeFoo();
+ }
+}
+ `,
+ options: [{ ignoreIfStatements: true }],
+ },
+ {
+ code: `
+declare let foo: { a: string } | null;
+declare function makeFoo(): { a: string };
+
+function lazyInitialize() {
+ if (!foo) foo = makeFoo();
+}
+ `,
+ options: [{ ignoreIfStatements: true }],
+ },
// ignoreConditionalTests
...nullishTypeTest((nullish, type, equals) => ({
From 221e8667be3ac092fd7f4a2013224c011cb6bd2d Mon Sep 17 00:00:00 2001
From: Olivier Zalmanski <88216225+OlivierZal@users.noreply.github.com>
Date: Thu, 27 Mar 2025 14:49:21 +0100
Subject: [PATCH 2/3] sorting
---
.../src/rules/prefer-nullish-coalescing.ts | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts
index 940566a801a8..b05e43d0431e 100644
--- a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts
+++ b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts
@@ -40,6 +40,7 @@ export type Options = [
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing?: boolean;
ignoreBooleanCoercion?: boolean;
ignoreConditionalTests?: boolean;
+ ignoreIfStatements?: boolean;
ignoreMixedLogicalExpressions?: boolean;
ignorePrimitives?:
| {
@@ -50,7 +51,6 @@ export type Options = [
}
| true;
ignoreTernaryTests?: boolean;
- ignoreIfStatements?: boolean;
},
];
@@ -103,6 +103,11 @@ export default createRule({
description:
'Whether to ignore cases that are located within a conditional test.',
},
+ ignoreIfStatements: {
+ type: 'boolean',
+ description:
+ 'Whether to ignore any if statements that could be simplified by using the nullish coalescing operator.',
+ },
ignoreMixedLogicalExpressions: {
type: 'boolean',
description:
@@ -146,11 +151,6 @@ export default createRule({
description:
'Whether to ignore any ternary expressions that could be simplified by using the nullish coalescing operator.',
},
- ignoreIfStatements: {
- type: 'boolean',
- description:
- 'Whether to ignore any if statements that could be simplified by using the nullish coalescing operator.',
- },
},
},
],
@@ -160,6 +160,7 @@ export default createRule({
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing: false,
ignoreBooleanCoercion: false,
ignoreConditionalTests: true,
+ ignoreIfStatements: false,
ignoreMixedLogicalExpressions: false,
ignorePrimitives: {
bigint: false,
@@ -168,7 +169,6 @@ export default createRule({
string: false,
},
ignoreTernaryTests: false,
- ignoreIfStatements: false,
},
],
create(
@@ -178,10 +178,10 @@ export default createRule({
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing,
ignoreBooleanCoercion,
ignoreConditionalTests,
+ ignoreIfStatements,
ignoreMixedLogicalExpressions,
ignorePrimitives,
ignoreTernaryTests,
- ignoreIfStatements,
},
],
) {
From 74b5b47f29492401314cc889eb35e5ea6d1308d9 Mon Sep 17 00:00:00 2001
From: Olivier Zalmanski <88216225+OlivierZal@users.noreply.github.com>
Date: Thu, 27 Mar 2025 16:30:05 +0100
Subject: [PATCH 3/3] update snapshots
---
.../docs/rules/prefer-nullish-coalescing.mdx | 18 ++++++------------
.../prefer-nullish-coalescing.shot | 18 ++++++------------
.../prefer-nullish-coalescing.shot | 6 ++++++
3 files changed, 18 insertions(+), 24 deletions(-)
diff --git a/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.mdx b/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.mdx
index 90c6094c38bb..5a99fe0259c6 100644
--- a/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.mdx
+++ b/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.mdx
@@ -131,17 +131,14 @@ Examples of code for this rule with `{ ignoreIfStatements: false }`:
declare let foo: { a: string } | null;
declare function makeFoo(): { a: string };
-function lazyInitializeFoo() {
+function lazyInitializeFoo1() {
if (!foo) {
foo = makeFoo();
}
}
-declare let bar: { a: string } | null;
-declare function makeBar(): { a: string };
-
-function lazyInitializeBar() {
- if (!bar) bar = makeBar();
+function lazyInitializeFoo2() {
+ if (!foo) foo = makeFoo();
}
```
@@ -152,15 +149,12 @@ function lazyInitializeBar() {
declare let foo: { a: string } | null;
declare function makeFoo(): { a: string };
-function lazyInitializeFoo() {
+function lazyInitializeFoo1() {
foo ??= makeFoo();
}
-declare let bar: { a: string } | null;
-declare function makeBar(): { a: string };
-
-function lazyInitializeBar() {
- bar ??= makeBar();
+function lazyInitializeFoo2() {
+ foo ??= makeFoo();
}
```
diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/prefer-nullish-coalescing.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/prefer-nullish-coalescing.shot
index 33092a4f6852..b3d8543af57d 100644
--- a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/prefer-nullish-coalescing.shot
+++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/prefer-nullish-coalescing.shot
@@ -107,7 +107,7 @@ Options: { "ignoreIfStatements": false }
declare let foo: { a: string } | null;
declare function makeFoo(): { a: string };
-function lazyInitializeFoo() {
+function lazyInitializeFoo1() {
if (!foo) {
~~~~~~~~~~~ Prefer using nullish coalescing operator (\`??=\`) instead of an assignment expression, as it is simpler to read.
foo = makeFoo();
@@ -116,11 +116,8 @@ function lazyInitializeFoo() {
~~~
}
-declare let bar: { a: string } | null;
-declare function makeBar(): { a: string };
-
-function lazyInitializeBar() {
- if (!bar) bar = makeBar();
+function lazyInitializeFoo2() {
+ if (!foo) foo = makeFoo();
~~~~~~~~~~~~~~~~~~~~~~~~~~ Prefer using nullish coalescing operator (\`??=\`) instead of an assignment expression, as it is simpler to read.
}
"
@@ -133,15 +130,12 @@ Options: { "ignoreIfStatements": false }
declare let foo: { a: string } | null;
declare function makeFoo(): { a: string };
-function lazyInitializeFoo() {
+function lazyInitializeFoo1() {
foo ??= makeFoo();
}
-declare let bar: { a: string } | null;
-declare function makeBar(): { a: string };
-
-function lazyInitializeBar() {
- bar ??= makeBar();
+function lazyInitializeFoo2() {
+ foo ??= makeFoo();
}
"
`;
diff --git a/packages/eslint-plugin/tests/schema-snapshots/prefer-nullish-coalescing.shot b/packages/eslint-plugin/tests/schema-snapshots/prefer-nullish-coalescing.shot
index ea441036f3a0..7c3b288ca1b4 100644
--- a/packages/eslint-plugin/tests/schema-snapshots/prefer-nullish-coalescing.shot
+++ b/packages/eslint-plugin/tests/schema-snapshots/prefer-nullish-coalescing.shot
@@ -20,6 +20,10 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos
"description": "Whether to ignore cases that are located within a conditional test.",
"type": "boolean"
},
+ "ignoreIfStatements": {
+ "description": "Whether to ignore any if statements that could be simplified by using the nullish coalescing operator.",
+ "type": "boolean"
+ },
"ignoreMixedLogicalExpressions": {
"description": "Whether to ignore any logical or expressions that are part of a mixed logical expression (with \`&&\`).",
"type": "boolean"
@@ -76,6 +80,8 @@ type Options = [
ignoreBooleanCoercion?: boolean;
/** Whether to ignore cases that are located within a conditional test. */
ignoreConditionalTests?: boolean;
+ /** Whether to ignore any if statements that could be simplified by using the nullish coalescing operator. */
+ ignoreIfStatements?: boolean;
/** Whether to ignore any logical or expressions that are part of a mixed logical expression (with \`&&\`). */
ignoreMixedLogicalExpressions?: boolean;
/** Whether to ignore all (\`true\`) or some (an object with properties) primitive types. */