Skip to content

Commit

Permalink
feat(eslint-plugin): add no-extra-non-null-assertion (#1183)
Browse files Browse the repository at this point in the history
Co-authored-by: Brad Zacher <brad.zacher@gmail.com>
  • Loading branch information
a-tarasyuk and bradzacher committed Nov 18, 2019
1 parent a9117f5 commit 2b3b5d6
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/eslint-plugin/README.md
Expand Up @@ -164,6 +164,7 @@ Then you should add `airbnb` (or `airbnb-base`) to your `extends` section of `.e
| [`@typescript-eslint/no-empty-function`](./docs/rules/no-empty-function.md) | Disallow empty functions | :heavy_check_mark: | | |
| [`@typescript-eslint/no-empty-interface`](./docs/rules/no-empty-interface.md) | Disallow the declaration of empty interfaces | :heavy_check_mark: | | |
| [`@typescript-eslint/no-explicit-any`](./docs/rules/no-explicit-any.md) | Disallow usage of the `any` type | :heavy_check_mark: | :wrench: | |
| [`@typescript-eslint/no-extra-non-null-assertion`](./docs/rules/no-extra-non-null-assertion.md) | Disallow extra non-null assertion | | | |
| [`@typescript-eslint/no-extra-parens`](./docs/rules/no-extra-parens.md) | Disallow unnecessary parentheses | | :wrench: | |
| [`@typescript-eslint/no-extraneous-class`](./docs/rules/no-extraneous-class.md) | Forbids the use of classes as namespaces | | | |
| [`@typescript-eslint/no-floating-promises`](./docs/rules/no-floating-promises.md) | Requires Promise-like values to be handled appropriately. | | | :thought_balloon: |
Expand Down
37 changes: 37 additions & 0 deletions packages/eslint-plugin/docs/rules/no-extra-non-null-assertion.md
@@ -0,0 +1,37 @@
# Disallow extra non-null assertion

## Rule Details

Examples of **incorrect** code for this rule:

```ts
const foo: { bar: number } | null = null;
const bar = foo!!!.bar;
```

```ts
function foo(bar: number | undefined) {
const bar: number = bar!!!;
}
```

Examples of **correct** code for this rule:

```ts
const foo: { bar: number } | null = null;
const bar = foo!.bar;
```

```ts
function foo(bar: number | undefined) {
const bar: number = bar!;
}
```

## How to use

```json
{
"@typescript-eslint/no-extra-non-null-assertion": ["error"]
}
```
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/configs/all.json
Expand Up @@ -32,6 +32,7 @@
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "error",
"no-extra-parens": "off",
"@typescript-eslint/no-extra-non-null-assertion": "error",
"@typescript-eslint/no-extra-parens": "error",
"@typescript-eslint/no-extraneous-class": "error",
"@typescript-eslint/no-floating-promises": "error",
Expand Down
2 changes: 2 additions & 0 deletions packages/eslint-plugin/src/rules/index.ts
Expand Up @@ -22,6 +22,7 @@ import noDynamicDelete from './no-dynamic-delete';
import noEmptyFunction from './no-empty-function';
import noEmptyInterface from './no-empty-interface';
import noExplicitAny from './no-explicit-any';
import noExtraNonNullAssertion from './no-extra-non-null-assertion';
import noExtraParens from './no-extra-parens';
import noExtraneousClass from './no-extraneous-class';
import noFloatingPromises from './no-floating-promises';
Expand Down Expand Up @@ -93,6 +94,7 @@ export default {
'no-empty-function': noEmptyFunction,
'no-empty-interface': noEmptyInterface,
'no-explicit-any': noExplicitAny,
'no-extra-non-null-assertion': noExtraNonNullAssertion,
'no-extra-parens': noExtraParens,
'no-extraneous-class': noExtraneousClass,
'no-floating-promises': noFloatingPromises,
Expand Down
25 changes: 25 additions & 0 deletions packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts
@@ -0,0 +1,25 @@
import * as util from '../util';

export default util.createRule({
name: 'no-extra-non-null-assertion',
meta: {
type: 'problem',
docs: {
description: 'Disallow extra non-null assertion',
category: 'Stylistic Issues',
recommended: false,
},
schema: [],
messages: {
noExtraNonNullAssertion: 'Forbidden extra non-null assertion.',
},
},
defaultOptions: [],
create(context) {
return {
'TSNonNullExpression > TSNonNullExpression'(node): void {
context.report({ messageId: 'noExtraNonNullAssertion', node });
},
};
},
});
@@ -0,0 +1,66 @@
import rule from '../../src/rules/no-extra-non-null-assertion';
import { RuleTester } from '../RuleTester';

const ruleTester = new RuleTester({
parser: '@typescript-eslint/parser',
});

ruleTester.run('no-extra-non-null-assertion', rule, {
valid: [
{
code: `
const foo: { bar: number } | null = null;
const bar = foo!.bar;
`,
},
{
code: `
function foo(bar: number | undefined) {
const bar: number = bar!;
} `,
},
],
invalid: [
{
code: `
const foo: { bar: number } | null = null;
const bar = foo!!!!.bar;
`,
errors: [
{
messageId: 'noExtraNonNullAssertion',
endColumn: 19,
column: 13,
line: 3,
},
{
messageId: 'noExtraNonNullAssertion',
endColumn: 18,
column: 13,
line: 3,
},
{
messageId: 'noExtraNonNullAssertion',
endColumn: 17,
column: 13,
line: 3,
},
],
},
{
code: `
function foo(bar: number | undefined) {
const bar: number = bar!!;
}
`,
errors: [
{
messageId: 'noExtraNonNullAssertion',
endColumn: 27,
column: 23,
line: 3,
},
],
},
],
});

0 comments on commit 2b3b5d6

Please sign in to comment.