Skip to content

⬅️ Back to Table of Contents

πŸ“„ no-meaningless-void-operator

πŸ“Š Analysis Summary

Metric Count
πŸ”§ Functions 3
πŸ“¦ Imports 6
πŸ“‘ Type Aliases 1

πŸ“š Table of Contents

πŸ› οΈ File Location:

πŸ“‚ packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts

πŸ“€ Default Export

export default createRule<Options, 'meaninglessVoidOnNonCall' | 'meaninglessVoidOperator' | 'removeVoid'>({ ... })
Property Value
name 'no-meaningless-void-operator'
meta.type 'suggestion'
meta.docs.description 'Disallow the void operator except when used to discard a value'
meta.docs.recommended 'strict'
meta.docs.requiresTypeChecking true
meta.fixable 'code'
meta.hasSuggestions true
meta.messages.meaninglessVoidOnNonCall "void operator is useless here; it should only discard a call's return value"
meta.messages.meaninglessVoidOperator "void operator shouldn't be used on {{type}}; it should convey that a return value is being ignored"
meta.messages.removeVoid "Remove 'void'"
meta.schema [ { type: 'object', additionalProperties: false, properties: { checkNever: { type: 'boolean', description: "Whether t...
defaultOptions [{ checkNever: false }]

Entry point: create β€” documented under Functions.


πŸ“¦ Imports

Name Source
TSESLint @typescript-eslint/utils
TSESTree @typescript-eslint/utils
AST_NODE_TYPES @typescript-eslint/utils
ESLintUtils @typescript-eslint/utils
createRule ../util
nullThrows ../util

Functions

create(context: any, [{ checkNever }]: any): { 'UnaryExpression[operator="void"]'(node: TSESTree.UnaryEx…

Parameters:

  • context any
  • [{ checkNever }] any

Returns: { 'UnaryExpression[operator="void"]'(node: TSESTree.UnaryExpression): void; }

Calls:

  • ESLintUtils.getParserServices
  • services.program.getTypeChecker
  • fixer.removeRange
  • context.sourceCode.getTokens
  • unwrapVoidArgument
  • services.esTreeNodeToTSNodeMap.get
  • services.getTypeAtLocation
  • tsutils.isThenableType
  • context.report
  • tsutils.unionConstituents
  • unionParts.every
  • tsutils.isTypeFlagSet
  • checker.typeToString

Internal Comments:

// `void 0` is a common undefined idiom, not a discarded call.
// Allow `void promiseValue` so this rule does not fight no-floating-promises.

Code
create(context, [{ checkNever }]) {
    const services = ESLintUtils.getParserServices(context);
    const checker = services.program.getTypeChecker();

    return {
      'UnaryExpression[operator="void"]'(node: TSESTree.UnaryExpression): void {
        const fix = (fixer: TSESLint.RuleFixer): TSESLint.RuleFix => {
          return fixer.removeRange([
            context.sourceCode.getTokens(node)[0].range[0],
            context.sourceCode.getTokens(node)[1].range[0],
          ]);
        };

        const inner = unwrapVoidArgument(node.argument);
        if (inner.type !== AST_NODE_TYPES.CallExpression) {
          // `void 0` is a common undefined idiom, not a discarded call.
          if (inner.type === AST_NODE_TYPES.Literal && inner.value === 0) {
            return;
          }

          const tsArgument = services.esTreeNodeToTSNodeMap.get(node.argument);
          const argType = services.getTypeAtLocation(node.argument);
          // Allow `void promiseValue` so this rule does not fight no-floating-promises.
          if (tsutils.isThenableType(checker, tsArgument, argType)) {
            return;
          }

          context.report({
            node,
            messageId: 'meaninglessVoidOnNonCall',
            fix:
              node.parent.type === AST_NODE_TYPES.ExpressionStatement
                ? fix
                : undefined,
          });
          return;
        }

        const argType = services.getTypeAtLocation(node.argument);
        const unionParts = tsutils.unionConstituents(argType);
        if (
          unionParts.every(part =>
            tsutils.isTypeFlagSet(
              part,
              ts.TypeFlags.Void | ts.TypeFlags.Undefined,
            ),
          )
        ) {
          context.report({
            node,
            messageId: 'meaninglessVoidOperator',
            data: { type: checker.typeToString(argType) },
            fix,
          });
        } else if (
          checkNever &&
          unionParts.every(part =>
            tsutils.isTypeFlagSet(
              part,
              ts.TypeFlags.Void | ts.TypeFlags.Undefined | ts.TypeFlags.Never,
            ),
          )
        ) {
          context.report({
            node,
            messageId: 'meaninglessVoidOperator',
            data: { type: checker.typeToString(argType) },
            suggest: [{ messageId: 'removeVoid', fix }],
          });
        }
      },
    };
  }

unwrapVoidArgument(node: TSESTree.Expression): TSESTree.Expression

Parameters:

  • node TSESTree.Expression

Returns: TSESTree.Expression

Calls:

  • nullThrows (from ../util)
  • current.expressions.at
Code
function unwrapVoidArgument(node: TSESTree.Expression): TSESTree.Expression {
  let current = node;
  while (true) {
    switch (current.type) {
      case AST_NODE_TYPES.ChainExpression:
      case AST_NODE_TYPES.TSAsExpression:
      case AST_NODE_TYPES.TSNonNullExpression:
      case AST_NODE_TYPES.TSSatisfiesExpression:
      case AST_NODE_TYPES.TSTypeAssertion:
        current = current.expression;
        continue;

      case AST_NODE_TYPES.SequenceExpression:
        current = nullThrows(
          current.expressions.at(-1),
          'Expected SequenceExpression to have at least one expression',
        );
        continue;

      default:
        return current;
    }
  }
}

Internal helpers

Declared inside another function in this file.

fix(fixer: TSESLint.RuleFixer): TSESLint.RuleFix

Parameters:

  • fixer TSESLint.RuleFixer

Returns: TSESLint.RuleFix

Calls:

  • fixer.removeRange
  • context.sourceCode.getTokens
Code
(fixer: TSESLint.RuleFixer): TSESLint.RuleFix => {
          return fixer.removeRange([
            context.sourceCode.getTokens(node)[0].range[0],
            context.sourceCode.getTokens(node)[1].range[0],
          ]);
        }

Type Aliases

Options

type Options = [
  {
    checkNever: boolean;
  },
];

Generated by Syntax Scribe