Skip to content

⬅️ Back to Table of Contents

📄 no-non-null-assertion

📊 Analysis Summary

Metric Count
🔧 Functions 3
📦 Imports 7
📑 Type Aliases 1

📚 Table of Contents

🛠️ File Location:

📂 packages/eslint-plugin/src/rules/no-non-null-assertion.ts

📤 Default Export

export default createRule<[], MessageIds>({ ... })
Property Value
name 'no-non-null-assertion'
meta.type 'problem'
meta.docs.description 'Disallow non-null assertions using the ! postfix operator'
meta.docs.recommended 'strict'
meta.hasSuggestions true
meta.messages.noNonNull 'Forbidden non-null assertion.'
meta.messages.suggestOptionalChain 'Consider using the optional chain operator ?. instead. This operator includes runtime checks, so it is safer than ...
meta.schema []
defaultOptions []

Entry point: create — documented under Functions.


📦 Imports

Name Source
TSESLint @typescript-eslint/utils
AST_NODE_TYPES @typescript-eslint/utils
createRule ../util
isAssignee ../util
isNonNullAssertionPunctuator ../util
nullThrows ../util
NullThrowsReasons ../util

Functions

create(context: any): { TSNonNullExpression(node: any): void; }

Parameters:

  • context any

Returns: { TSNonNullExpression(node: any): void; }

Calls:

  • nullThrows (from ../util)
  • context.sourceCode.getTokenAfter
  • NullThrowsReasons.MissingToken
  • fixer.replaceText
  • fixer.remove
  • isAssignee (from ../util)
  • suggest.push
  • replaceTokenWithOptional
  • fixer.insertTextBefore
  • removeToken
  • context.report

Internal Comments:

// it always exists in non-null assertion (x2)
// it is x![y]?.z (x4)
// it is x!.y?.z (x4)
// x!.y?.z (x2)
//   ^ punctuator (x2)
// it is x!?.[y].z or  x!?.y.z (x4)
// it is x.y?.z!() (x4)
// it is x.y.z!?.() (x4)

Code
create(context) {
    return {
      TSNonNullExpression(node): void {
        const suggest: TSESLint.ReportSuggestionArray<MessageIds> = [];

        // it always exists in non-null assertion
        const nonNullOperator = nullThrows(
          context.sourceCode.getTokenAfter(
            node.expression,
            isNonNullAssertionPunctuator,
          ),
          NullThrowsReasons.MissingToken('!', 'expression'),
        );

        function replaceTokenWithOptional(): TSESLint.ReportFixFunction {
          return fixer => fixer.replaceText(nonNullOperator, '?.');
        }

        function removeToken(): TSESLint.ReportFixFunction {
          return fixer => fixer.remove(nonNullOperator);
        }

        if (
          node.parent.type === AST_NODE_TYPES.MemberExpression &&
          node.parent.object === node &&
          !isAssignee(node.parent)
        ) {
          if (!node.parent.optional) {
            if (node.parent.computed) {
              // it is x![y]?.z
              suggest.push({
                messageId: 'suggestOptionalChain',
                fix: replaceTokenWithOptional(),
              });
            } else {
              // it is x!.y?.z
              suggest.push({
                messageId: 'suggestOptionalChain',
                fix(fixer) {
                  // x!.y?.z
                  //   ^ punctuator
                  const punctuator = nullThrows(
                    context.sourceCode.getTokenAfter(nonNullOperator),
                    NullThrowsReasons.MissingToken('.', '!'),
                  );
                  return [
                    fixer.remove(nonNullOperator),
                    fixer.insertTextBefore(punctuator, '?'),
                  ];
                },
              });
            }
          } else {
            // it is x!?.[y].z or  x!?.y.z
            suggest.push({
              messageId: 'suggestOptionalChain',
              fix: removeToken(),
            });
          }
        } else if (
          node.parent.type === AST_NODE_TYPES.CallExpression &&
          node.parent.callee === node
        ) {
          if (!node.parent.optional) {
            // it is x.y?.z!()
            suggest.push({
              messageId: 'suggestOptionalChain',
              fix: replaceTokenWithOptional(),
            });
          } else {
            // it is x.y.z!?.()
            suggest.push({
              messageId: 'suggestOptionalChain',
              fix: removeToken(),
            });
          }
        }

        context.report({
          node,
          messageId: 'noNonNull',
          suggest,
        });
      },
    };
  }

Internal helpers

Declared inside another function in this file.

replaceTokenWithOptional(): TSESLint.ReportFixFunction

Returns: TSESLint.ReportFixFunction

Calls:

  • fixer.replaceText
Code
function replaceTokenWithOptional(): TSESLint.ReportFixFunction {
          return fixer => fixer.replaceText(nonNullOperator, '?.');
        }

removeToken(): TSESLint.ReportFixFunction

Returns: TSESLint.ReportFixFunction

Calls:

  • fixer.remove
Code
function removeToken(): TSESLint.ReportFixFunction {
          return fixer => fixer.remove(nonNullOperator);
        }

Type Aliases

MessageIds

type MessageIds = 'noNonNull' | 'suggestOptionalChain';

Generated by Syntax Scribe