Skip to content

Commit 2b3b5d6

Browse files
feat(eslint-plugin): add no-extra-non-null-assertion (typescript-eslint#1183)
Co-authored-by: Brad Zacher <brad.zacher@gmail.com>
1 parent a9117f5 commit 2b3b5d6

File tree

6 files changed

+132
-0
lines changed

6 files changed

+132
-0
lines changed

packages/eslint-plugin/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ Then you should add `airbnb` (or `airbnb-base`) to your `extends` section of `.e
164164
| [`@typescript-eslint/no-empty-function`](./docs/rules/no-empty-function.md) | Disallow empty functions | :heavy_check_mark: | | |
165165
| [`@typescript-eslint/no-empty-interface`](./docs/rules/no-empty-interface.md) | Disallow the declaration of empty interfaces | :heavy_check_mark: | | |
166166
| [`@typescript-eslint/no-explicit-any`](./docs/rules/no-explicit-any.md) | Disallow usage of the `any` type | :heavy_check_mark: | :wrench: | |
167+
| [`@typescript-eslint/no-extra-non-null-assertion`](./docs/rules/no-extra-non-null-assertion.md) | Disallow extra non-null assertion | | | |
167168
| [`@typescript-eslint/no-extra-parens`](./docs/rules/no-extra-parens.md) | Disallow unnecessary parentheses | | :wrench: | |
168169
| [`@typescript-eslint/no-extraneous-class`](./docs/rules/no-extraneous-class.md) | Forbids the use of classes as namespaces | | | |
169170
| [`@typescript-eslint/no-floating-promises`](./docs/rules/no-floating-promises.md) | Requires Promise-like values to be handled appropriately. | | | :thought_balloon: |
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Disallow extra non-null assertion
2+
3+
## Rule Details
4+
5+
Examples of **incorrect** code for this rule:
6+
7+
```ts
8+
const foo: { bar: number } | null = null;
9+
const bar = foo!!!.bar;
10+
```
11+
12+
```ts
13+
function foo(bar: number | undefined) {
14+
const bar: number = bar!!!;
15+
}
16+
```
17+
18+
Examples of **correct** code for this rule:
19+
20+
```ts
21+
const foo: { bar: number } | null = null;
22+
const bar = foo!.bar;
23+
```
24+
25+
```ts
26+
function foo(bar: number | undefined) {
27+
const bar: number = bar!;
28+
}
29+
```
30+
31+
## How to use
32+
33+
```json
34+
{
35+
"@typescript-eslint/no-extra-non-null-assertion": ["error"]
36+
}
37+
```

packages/eslint-plugin/src/configs/all.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"@typescript-eslint/no-empty-interface": "error",
3333
"@typescript-eslint/no-explicit-any": "error",
3434
"no-extra-parens": "off",
35+
"@typescript-eslint/no-extra-non-null-assertion": "error",
3536
"@typescript-eslint/no-extra-parens": "error",
3637
"@typescript-eslint/no-extraneous-class": "error",
3738
"@typescript-eslint/no-floating-promises": "error",

packages/eslint-plugin/src/rules/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import noDynamicDelete from './no-dynamic-delete';
2222
import noEmptyFunction from './no-empty-function';
2323
import noEmptyInterface from './no-empty-interface';
2424
import noExplicitAny from './no-explicit-any';
25+
import noExtraNonNullAssertion from './no-extra-non-null-assertion';
2526
import noExtraParens from './no-extra-parens';
2627
import noExtraneousClass from './no-extraneous-class';
2728
import noFloatingPromises from './no-floating-promises';
@@ -93,6 +94,7 @@ export default {
9394
'no-empty-function': noEmptyFunction,
9495
'no-empty-interface': noEmptyInterface,
9596
'no-explicit-any': noExplicitAny,
97+
'no-extra-non-null-assertion': noExtraNonNullAssertion,
9698
'no-extra-parens': noExtraParens,
9799
'no-extraneous-class': noExtraneousClass,
98100
'no-floating-promises': noFloatingPromises,
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import * as util from '../util';
2+
3+
export default util.createRule({
4+
name: 'no-extra-non-null-assertion',
5+
meta: {
6+
type: 'problem',
7+
docs: {
8+
description: 'Disallow extra non-null assertion',
9+
category: 'Stylistic Issues',
10+
recommended: false,
11+
},
12+
schema: [],
13+
messages: {
14+
noExtraNonNullAssertion: 'Forbidden extra non-null assertion.',
15+
},
16+
},
17+
defaultOptions: [],
18+
create(context) {
19+
return {
20+
'TSNonNullExpression > TSNonNullExpression'(node): void {
21+
context.report({ messageId: 'noExtraNonNullAssertion', node });
22+
},
23+
};
24+
},
25+
});
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import rule from '../../src/rules/no-extra-non-null-assertion';
2+
import { RuleTester } from '../RuleTester';
3+
4+
const ruleTester = new RuleTester({
5+
parser: '@typescript-eslint/parser',
6+
});
7+
8+
ruleTester.run('no-extra-non-null-assertion', rule, {
9+
valid: [
10+
{
11+
code: `
12+
const foo: { bar: number } | null = null;
13+
const bar = foo!.bar;
14+
`,
15+
},
16+
{
17+
code: `
18+
function foo(bar: number | undefined) {
19+
const bar: number = bar!;
20+
} `,
21+
},
22+
],
23+
invalid: [
24+
{
25+
code: `
26+
const foo: { bar: number } | null = null;
27+
const bar = foo!!!!.bar;
28+
`,
29+
errors: [
30+
{
31+
messageId: 'noExtraNonNullAssertion',
32+
endColumn: 19,
33+
column: 13,
34+
line: 3,
35+
},
36+
{
37+
messageId: 'noExtraNonNullAssertion',
38+
endColumn: 18,
39+
column: 13,
40+
line: 3,
41+
},
42+
{
43+
messageId: 'noExtraNonNullAssertion',
44+
endColumn: 17,
45+
column: 13,
46+
line: 3,
47+
},
48+
],
49+
},
50+
{
51+
code: `
52+
function foo(bar: number | undefined) {
53+
const bar: number = bar!!;
54+
}
55+
`,
56+
errors: [
57+
{
58+
messageId: 'noExtraNonNullAssertion',
59+
endColumn: 27,
60+
column: 23,
61+
line: 3,
62+
},
63+
],
64+
},
65+
],
66+
});

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy