Skip to content

⬅️ Back to Table of Contents

📄 no-confusing-void-expression

📊 Analysis Summary

Metric Count
🔧 Functions 8
📦 Imports 11
📑 Type Aliases 4

📚 Table of Contents

🛠️ File Location:

📂 packages/eslint-plugin/src/rules/no-confusing-void-expression.ts

📤 Default Export

export default createRule<Options, MessageId>({ ... })
Property Value
name 'no-confusing-void-expression'
meta.type 'problem'
meta.docs.description 'Require expressions of type void to appear in statement position'
meta.docs.recommended 'strict'
meta.docs.requiresTypeChecking true
meta.fixable 'code'
meta.hasSuggestions true
meta.messages.invalidVoidExpr 'Placing a void expression inside another expression is forbidden. ' + 'Move it to its own statement instead.'
meta.messages.invalidVoidExprArrow 'Returning a void expression from an arrow function shorthand is forbidden. ' + 'Please add braces to the arrow funct...
meta.messages.invalidVoidExprArrowWrapVoid 'Void expressions returned from an arrow function shorthand ' + 'must be marked explicitly with the void operator.'
meta.messages.invalidVoidExprReturn 'Returning a void expression from a function is forbidden. ' + 'Please move it before the return statement.'
meta.messages.invalidVoidExprReturnLast 'Returning a void expression from a function is forbidden. ' + 'Please remove the return statement.'
meta.messages.invalidVoidExprReturnWrapVoid 'Void expressions returned from a function ' + 'must be marked explicitly with the void operator.'
meta.messages.invalidVoidExprWrapVoid 'Void expressions used inside another expression ' + 'must be moved to its own statement ' + 'or marked explicitly wi...
meta.messages.voidExprWrapVoid 'Mark with an explicit void operator.'
meta.schema [ { type: 'object', additionalProperties: false, properties: { ignoreArrowShorthand: { type: 'boolean', description: ...
defaultOptions [ { ignoreArrowShorthand: false, ignoreVoidOperator: false, ignoreVoidReturningFunctions: false, }, ]

Entry point: create — documented under Functions.


📦 Imports

Name Source
NodeWithParent @typescript-eslint/utils
TSESLint @typescript-eslint/utils
TSESTree @typescript-eslint/utils
AST_NODE_TYPES @typescript-eslint/utils
MakeRequired ../util
createRule ../util
getConstrainedTypeAtLocation ../util
getParserServices ../util
nullThrows ../util
NullThrowsReasons ../util
getParentFunctionNode ../util/getParentFunctionNode

Functions

create(context: any, [options]: any): { 'AwaitExpression, CallExpression, TaggedTemplateExpressio…

Parameters:

  • context any
  • [options] any

Returns: { 'AwaitExpression, CallExpression, TaggedTemplateExpression'(node: TSESTree.AwaitExpression | TSESTree.CallExpression | TSESTree.TaggedTemplateExpression): void; }

Calls:

  • getParserServices (from ../util)
  • findInvalidAncestor
  • getConstrainedTypeAtLocation (from ../util)
  • tsutils.isTypeFlagSet
  • context.sourceCode.getText
  • fixer.replaceText
  • isVoidReturningFunctionNode
  • context.report
  • canFix
  • nullThrows (from ../util)
  • context.sourceCode.getTokenBefore
  • NullThrowsReasons.MissingToken
  • fixer.replaceTextRange
  • getParentFunctionNode (from ../util/getParentFunctionNode)
  • isFinalReturn
  • isPreventingASI
  • [ AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionDeclaration, AST_NODE_TYPES.FunctionExpression, ].includes
  • block.body.indexOf
  • context.sourceCode.getFirstToken
  • ['(', '[', ''].includes`
  • tsutils.getCallSignaturesOfType
  • callSignatures.some
  • signature.getReturnType
  • tsutils .unionConstituents(returnType) .some
  • services.getTypeFromTypeNode
  • services.getContextualType
  • tsutils .unionConstituents(functionType) .some

Internal Comments:

// void expression is in valid position
// not a void expression
// handle arrow function shorthand
// handle wrapping with `void` (x2)
// handle wrapping with braces (x2)
// handle return statement
// remove the `return` keyword
// put a semicolon at the beginning of the line (x6)
// move before the `return` keyword
// e.g. `if (cond) return console.error();` (x3)
// add braces if not inside a block (x3)
// handle generic case
// this would be reported by this rule btw. such irony
/**
     * Inspects the void expression's ancestors and finds closest invalid one.
     * By default anything other than an ExpressionStatement is invalid.
     * Parent expressions which can be used for their short-circuiting behavior
     * are ignored and their parents are checked instead.
     * @param node The void expression node to check.
     * @returns Invalid ancestor node if it was found. `null` otherwise.
     */
// e.g. `{ console.log("foo"); }`
// this is always valid
// e.g. `x && console.log(x)`
// this is valid only if the next ancestor is valid (x2)
// e.g. `cond ? console.log(true) : console.log(false)`
// e.g. `() => console.log("foo")` (x2)
// this is valid with an appropriate option (x4)
// e.g. `void console.log("foo")` (x2)
// e.g. `console?.log('foo')`
// Any other parent is invalid.
// We can assume a return statement will have an argument.
/** Checks whether the return statement is the last statement in a function body. */
// the parent must be a block (x2)
// e.g. `if (cond) return;` (not in a block)
// the block's parent must be a function (x2)
// e.g. `if (cond) { return; }`
// not in a top-level function block
// must be the last child of the block
// not the last statement in the block
/**
     * Checks whether the given node, if placed on its own line,
     * would prevent automatic semicolon insertion on the line before.
     *
     * This happens if the line begins with `(`, `[` or `` ` ``
     */
// Game plan:
//   - If the function node has a type annotation, check if it includes `void`.
//     - If it does then the function is safe to return `void` expressions in.
//   - Otherwise, check if the function is a function-expression or an arrow-function.
//   -   If it is, get its contextual type and bail if we cannot.
//   - Return based on whether the contextual type includes `void` or not

Code
create(context, [options]) {
    const services = getParserServices(context);

    return {
      'AwaitExpression, CallExpression, TaggedTemplateExpression'(
        node:
          | TSESTree.AwaitExpression
          | TSESTree.CallExpression
          | TSESTree.TaggedTemplateExpression,
      ): void {
        const invalidAncestor = findInvalidAncestor(node);
        if (invalidAncestor == null) {
          // void expression is in valid position
          return;
        }

        const type = getConstrainedTypeAtLocation(services, node);
        if (!tsutils.isTypeFlagSet(type, ts.TypeFlags.VoidLike)) {
          // not a void expression
          return;
        }

        const wrapVoidFix = (fixer: TSESLint.RuleFixer): TSESLint.RuleFix => {
          const nodeText = context.sourceCode.getText(node);
          const newNodeText = `void ${nodeText}`;
          return fixer.replaceText(node, newNodeText);
        };

        if (invalidAncestor.type === AST_NODE_TYPES.ArrowFunctionExpression) {
          // handle arrow function shorthand

          if (options.ignoreVoidReturningFunctions) {
            const returnsVoid = isVoidReturningFunctionNode(invalidAncestor);

            if (returnsVoid) {
              return;
            }
          }

          if (options.ignoreVoidOperator) {
            // handle wrapping with `void`
            return context.report({
              node,
              messageId: 'invalidVoidExprArrowWrapVoid',
              fix: wrapVoidFix,
            });
          }

          // handle wrapping with braces
          const arrowFunction = invalidAncestor;
          return context.report({
            node,
            messageId: 'invalidVoidExprArrow',
            fix(fixer) {
              if (!canFix(arrowFunction)) {
                return null;
              }
              const arrowToken = nullThrows(
                context.sourceCode.getTokenBefore(arrowFunction.body, {
                  filter: token => token.value === '=>',
                }),
                NullThrowsReasons.MissingToken(
                  'arrow token',
                  'before arrow function body',
                ),
              );
              return [
                fixer.replaceTextRange(
                  [arrowToken.range[1], arrowFunction.body.range[0]],
                  ' { ',
                ),
                fixer.replaceTextRange(
                  [arrowFunction.body.range[1], arrowFunction.range[1]],
                  '; }',
                ),
              ];
            },
          });
        }

        if (invalidAncestor.type === AST_NODE_TYPES.ReturnStatement) {
          // handle return statement

          if (options.ignoreVoidReturningFunctions) {
            const functionNode = getParentFunctionNode(invalidAncestor);

            if (functionNode) {
              const returnsVoid = isVoidReturningFunctionNode(functionNode);

              if (returnsVoid) {
                return;
              }
            }
          }

          if (options.ignoreVoidOperator) {
            // handle wrapping with `void`
            return context.report({
              node,
              messageId: 'invalidVoidExprReturnWrapVoid',
              fix: wrapVoidFix,
            });
          }

          if (isFinalReturn(invalidAncestor)) {
            // remove the `return` keyword
            return context.report({
              node,
              messageId: 'invalidVoidExprReturnLast',
              fix(fixer) {
                if (!canFix(invalidAncestor)) {
                  return null;
                }
                const returnValue = invalidAncestor.argument;
                const returnValueText = context.sourceCode.getText(returnValue);
                let newReturnStmtText = `${returnValueText};`;
                if (isPreventingASI(returnValue)) {
                  // put a semicolon at the beginning of the line
                  newReturnStmtText = `;${newReturnStmtText}`;
                }
                return fixer.replaceText(invalidAncestor, newReturnStmtText);
              },
            });
          }

          // move before the `return` keyword
          return context.report({
            node,
            messageId: 'invalidVoidExprReturn',
            fix(fixer) {
              const returnValue = invalidAncestor.argument;
              const returnValueText = context.sourceCode.getText(returnValue);
              let newReturnStmtText = `${returnValueText}; return;`;
              if (isPreventingASI(returnValue)) {
                // put a semicolon at the beginning of the line
                newReturnStmtText = `;${newReturnStmtText}`;
              }
              if (
                invalidAncestor.parent.type !== AST_NODE_TYPES.BlockStatement
              ) {
                // e.g. `if (cond) return console.error();`
                // add braces if not inside a block
                newReturnStmtText = `{ ${newReturnStmtText} }`;
              }
              return fixer.replaceText(invalidAncestor, newReturnStmtText);
            },
          });
        }

        // handle generic case
        if (options.ignoreVoidOperator) {
          // this would be reported by this rule btw. such irony
          return context.report({
            node,
            messageId: 'invalidVoidExprWrapVoid',
            suggest: [{ messageId: 'voidExprWrapVoid', fix: wrapVoidFix }],
          });
        }

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

    type ReturnStatementWithArgument = MakeRequired<
      TSESTree.ReturnStatement,
      'argument'
    >;

    type InvalidAncestor =
      | Exclude<TSESTree.Node, TSESTree.ReturnStatement>
      | ReturnStatementWithArgument;

    /**
     * Inspects the void expression's ancestors and finds closest invalid one.
     * By default anything other than an ExpressionStatement is invalid.
     * Parent expressions which can be used for their short-circuiting behavior
     * are ignored and their parents are checked instead.
     * @param node The void expression node to check.
     * @returns Invalid ancestor node if it was found. `null` otherwise.
     */
    function findInvalidAncestor(node: NodeWithParent): InvalidAncestor | null {
      const parent = node.parent;
      if (
        parent.type === AST_NODE_TYPES.SequenceExpression &&
        node !== parent.expressions[parent.expressions.length - 1]
      ) {
        return null;
      }

      if (parent.type === AST_NODE_TYPES.ExpressionStatement) {
        // e.g. `{ console.log("foo"); }`
        // this is always valid
        return null;
      }

      if (
        parent.type === AST_NODE_TYPES.LogicalExpression &&
        parent.right === node
      ) {
        // e.g. `x && console.log(x)`
        // this is valid only if the next ancestor is valid
        return findInvalidAncestor(parent);
      }

      if (
        parent.type === AST_NODE_TYPES.ConditionalExpression &&
        (parent.consequent === node || parent.alternate === node)
      ) {
        // e.g. `cond ? console.log(true) : console.log(false)`
        // this is valid only if the next ancestor is valid
        return findInvalidAncestor(parent);
      }

      if (
        parent.type === AST_NODE_TYPES.ArrowFunctionExpression &&
        // e.g. `() => console.log("foo")`
        // this is valid with an appropriate option
        options.ignoreArrowShorthand
      ) {
        return null;
      }

      if (
        parent.type === AST_NODE_TYPES.UnaryExpression &&
        parent.operator === 'void' &&
        // e.g. `void console.log("foo")`
        // this is valid with an appropriate option
        options.ignoreVoidOperator
      ) {
        return null;
      }

      if (parent.type === AST_NODE_TYPES.ChainExpression) {
        // e.g. `console?.log('foo')`
        return findInvalidAncestor(parent);
      }

      // Any other parent is invalid.
      // We can assume a return statement will have an argument.
      return parent as InvalidAncestor;
    }

    /** Checks whether the return statement is the last statement in a function body. */
    function isFinalReturn(node: TSESTree.ReturnStatement): boolean {
      // the parent must be a block
      const block = node.parent;
      if (block.type !== AST_NODE_TYPES.BlockStatement) {
        // e.g. `if (cond) return;` (not in a block)
        return false;
      }

      // the block's parent must be a function
      const blockParent = block.parent;
      if (
        ![
          AST_NODE_TYPES.ArrowFunctionExpression,
          AST_NODE_TYPES.FunctionDeclaration,
          AST_NODE_TYPES.FunctionExpression,
        ].includes(blockParent.type)
      ) {
        // e.g. `if (cond) { return; }`
        // not in a top-level function block
        return false;
      }

      // must be the last child of the block
      if (block.body.indexOf(node) < block.body.length - 1) {
        // not the last statement in the block
        return false;
      }

      return true;
    }

    /**
     * Checks whether the given node, if placed on its own line,
     * would prevent automatic semicolon insertion on the line before.
     *
     * This happens if the line begins with `(`, `[` or `` ` ``
     */
    function isPreventingASI(node: TSESTree.Expression): boolean {
      const startToken = nullThrows(
        context.sourceCode.getFirstToken(node),
        NullThrowsReasons.MissingToken('first token', node.type),
      );

      return ['(', '[', '`'].includes(startToken.value);
    }

    function canFix(
      node: ReturnStatementWithArgument | TSESTree.ArrowFunctionExpression,
    ): boolean {
      const targetNode =
        node.type === AST_NODE_TYPES.ReturnStatement
          ? node.argument
          : node.body;

      const type = getConstrainedTypeAtLocation(services, targetNode);
      return tsutils.isTypeFlagSet(type, ts.TypeFlags.VoidLike);
    }

    function isFunctionReturnTypeIncludesVoid(functionType: ts.Type): boolean {
      const callSignatures = tsutils.getCallSignaturesOfType(functionType);

      return callSignatures.some(signature => {
        const returnType = signature.getReturnType();

        return tsutils
          .unionConstituents(returnType)
          .some(tsutils.isIntrinsicVoidType);
      });
    }

    function isVoidReturningFunctionNode(
      functionNode:
        | TSESTree.ArrowFunctionExpression
        | TSESTree.FunctionDeclaration
        | TSESTree.FunctionExpression,
    ): boolean {
      // Game plan:
      //   - If the function node has a type annotation, check if it includes `void`.
      //     - If it does then the function is safe to return `void` expressions in.
      //   - Otherwise, check if the function is a function-expression or an arrow-function.
      //   -   If it is, get its contextual type and bail if we cannot.
      //   - Return based on whether the contextual type includes `void` or not
      if (functionNode.returnType) {
        const returnType = services.getTypeFromTypeNode(
          functionNode.returnType.typeAnnotation,
        );

        return tsutils
          .unionConstituents(returnType)
          .some(tsutils.isIntrinsicVoidType);
      }

      if (functionNode.type !== AST_NODE_TYPES.FunctionDeclaration) {
        const functionType = services.getContextualType(functionNode);

        if (functionType) {
          return tsutils
            .unionConstituents(functionType)
            .some(isFunctionReturnTypeIncludesVoid);
        }
      }

      return false;
    }
  }

Internal helpers

Declared inside another function in this file.

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

Parameters:

  • fixer TSESLint.RuleFixer

Returns: TSESLint.RuleFix

Calls:

  • context.sourceCode.getText
  • fixer.replaceText
Code
(fixer: TSESLint.RuleFixer): TSESLint.RuleFix => {
          const nodeText = context.sourceCode.getText(node);
          const newNodeText = `void ${nodeText}`;
          return fixer.replaceText(node, newNodeText);
        }

findInvalidAncestor(node: NodeWithParent): InvalidAncestor | null

Inspects the void expression's ancestors and finds closest invalid one. By default anything other than an ExpressionStatement is invalid. Parent expressions which can be used for their short-circuiting behavior are ignored and their parents are checked instead.

Parameters:

  • node any: The void expression node to check.

Returns: undefined Invalid ancestor node if it was found. null otherwise.

Raw JSDoc
/**
     * Inspects the void expression's ancestors and finds closest invalid one.
     * By default anything other than an ExpressionStatement is invalid.
     * Parent expressions which can be used for their short-circuiting behavior
     * are ignored and their parents are checked instead.
     * @param node The void expression node to check.
     * @returns Invalid ancestor node if it was found. `null` otherwise.
     */

Calls:

  • findInvalidAncestor

Internal Comments:

// e.g. `{ console.log("foo"); }`
// this is always valid
// e.g. `x && console.log(x)`
// this is valid only if the next ancestor is valid (x2)
// e.g. `cond ? console.log(true) : console.log(false)`
// e.g. `() => console.log("foo")` (x2)
// this is valid with an appropriate option (x4)
// e.g. `void console.log("foo")` (x2)
// e.g. `console?.log('foo')`
// Any other parent is invalid.
// We can assume a return statement will have an argument.

Code
function findInvalidAncestor(node: NodeWithParent): InvalidAncestor | null {
      const parent = node.parent;
      if (
        parent.type === AST_NODE_TYPES.SequenceExpression &&
        node !== parent.expressions[parent.expressions.length - 1]
      ) {
        return null;
      }

      if (parent.type === AST_NODE_TYPES.ExpressionStatement) {
        // e.g. `{ console.log("foo"); }`
        // this is always valid
        return null;
      }

      if (
        parent.type === AST_NODE_TYPES.LogicalExpression &&
        parent.right === node
      ) {
        // e.g. `x && console.log(x)`
        // this is valid only if the next ancestor is valid
        return findInvalidAncestor(parent);
      }

      if (
        parent.type === AST_NODE_TYPES.ConditionalExpression &&
        (parent.consequent === node || parent.alternate === node)
      ) {
        // e.g. `cond ? console.log(true) : console.log(false)`
        // this is valid only if the next ancestor is valid
        return findInvalidAncestor(parent);
      }

      if (
        parent.type === AST_NODE_TYPES.ArrowFunctionExpression &&
        // e.g. `() => console.log("foo")`
        // this is valid with an appropriate option
        options.ignoreArrowShorthand
      ) {
        return null;
      }

      if (
        parent.type === AST_NODE_TYPES.UnaryExpression &&
        parent.operator === 'void' &&
        // e.g. `void console.log("foo")`
        // this is valid with an appropriate option
        options.ignoreVoidOperator
      ) {
        return null;
      }

      if (parent.type === AST_NODE_TYPES.ChainExpression) {
        // e.g. `console?.log('foo')`
        return findInvalidAncestor(parent);
      }

      // Any other parent is invalid.
      // We can assume a return statement will have an argument.
      return parent as InvalidAncestor;
    }

isFinalReturn(node: TSESTree.ReturnStatement): boolean

Checks whether the return statement is the last statement in a function body.

Raw JSDoc
/** Checks whether the return statement is the last statement in a function body. */

Calls:

  • [ AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionDeclaration, AST_NODE_TYPES.FunctionExpression, ].includes
  • block.body.indexOf

Internal Comments:

// the parent must be a block (x2)
// e.g. `if (cond) return;` (not in a block)
// the block's parent must be a function (x2)
// e.g. `if (cond) { return; }`
// not in a top-level function block
// must be the last child of the block
// not the last statement in the block

Code
function isFinalReturn(node: TSESTree.ReturnStatement): boolean {
      // the parent must be a block
      const block = node.parent;
      if (block.type !== AST_NODE_TYPES.BlockStatement) {
        // e.g. `if (cond) return;` (not in a block)
        return false;
      }

      // the block's parent must be a function
      const blockParent = block.parent;
      if (
        ![
          AST_NODE_TYPES.ArrowFunctionExpression,
          AST_NODE_TYPES.FunctionDeclaration,
          AST_NODE_TYPES.FunctionExpression,
        ].includes(blockParent.type)
      ) {
        // e.g. `if (cond) { return; }`
        // not in a top-level function block
        return false;
      }

      // must be the last child of the block
      if (block.body.indexOf(node) < block.body.length - 1) {
        // not the last statement in the block
        return false;
      }

      return true;
    }

isPreventingASI(node: TSESTree.Expression): boolean

Checks whether the given node, if placed on its own line, would prevent automatic semicolon insertion on the line before.

This happens if the line begins with (, [ or `

Raw JSDoc
/**
     * Checks whether the given node, if placed on its own line,
     * would prevent automatic semicolon insertion on the line before.
     *
     * This happens if the line begins with `(`, `[` or `` ` ``
     */

Calls:

  • nullThrows (from ../util)
  • context.sourceCode.getFirstToken
  • NullThrowsReasons.MissingToken
  • ['(', '[', ''].includes`
Code
function isPreventingASI(node: TSESTree.Expression): boolean {
      const startToken = nullThrows(
        context.sourceCode.getFirstToken(node),
        NullThrowsReasons.MissingToken('first token', node.type),
      );

      return ['(', '[', '`'].includes(startToken.value);
    }

canFix(node: ReturnStatementWithArgument | TSESTree.…): boolean

Parameters:

  • node ReturnStatementWithArgument | TSESTree.ArrowFunctionExpression

Returns: boolean

Calls:

  • getConstrainedTypeAtLocation (from ../util)
  • tsutils.isTypeFlagSet
Code
function canFix(
      node: ReturnStatementWithArgument | TSESTree.ArrowFunctionExpression,
    ): boolean {
      const targetNode =
        node.type === AST_NODE_TYPES.ReturnStatement
          ? node.argument
          : node.body;

      const type = getConstrainedTypeAtLocation(services, targetNode);
      return tsutils.isTypeFlagSet(type, ts.TypeFlags.VoidLike);
    }

isFunctionReturnTypeIncludesVoid(functionType: ts.Type): boolean

Parameters:

  • functionType ts.Type

Returns: boolean

Calls:

  • tsutils.getCallSignaturesOfType
  • callSignatures.some
  • signature.getReturnType
  • tsutils .unionConstituents(returnType) .some
Code
function isFunctionReturnTypeIncludesVoid(functionType: ts.Type): boolean {
      const callSignatures = tsutils.getCallSignaturesOfType(functionType);

      return callSignatures.some(signature => {
        const returnType = signature.getReturnType();

        return tsutils
          .unionConstituents(returnType)
          .some(tsutils.isIntrinsicVoidType);
      });
    }

isVoidReturningFunctionNode(functionNode: | TSESTree.ArrowFunctionExpression | TS…): boolean

Parameters:

  • functionNode | TSESTree.ArrowFunctionExpression | TSESTree.FunctionDeclaration | TSESTree.FunctionExpression

Returns: boolean

Calls:

  • services.getTypeFromTypeNode
  • tsutils .unionConstituents(returnType) .some
  • services.getContextualType
  • tsutils .unionConstituents(functionType) .some

Internal Comments:

// Game plan:
//   - If the function node has a type annotation, check if it includes `void`.
//     - If it does then the function is safe to return `void` expressions in.
//   - Otherwise, check if the function is a function-expression or an arrow-function.
//   -   If it is, get its contextual type and bail if we cannot.
//   - Return based on whether the contextual type includes `void` or not

Code
function isVoidReturningFunctionNode(
      functionNode:
        | TSESTree.ArrowFunctionExpression
        | TSESTree.FunctionDeclaration
        | TSESTree.FunctionExpression,
    ): boolean {
      // Game plan:
      //   - If the function node has a type annotation, check if it includes `void`.
      //     - If it does then the function is safe to return `void` expressions in.
      //   - Otherwise, check if the function is a function-expression or an arrow-function.
      //   -   If it is, get its contextual type and bail if we cannot.
      //   - Return based on whether the contextual type includes `void` or not
      if (functionNode.returnType) {
        const returnType = services.getTypeFromTypeNode(
          functionNode.returnType.typeAnnotation,
        );

        return tsutils
          .unionConstituents(returnType)
          .some(tsutils.isIntrinsicVoidType);
      }

      if (functionNode.type !== AST_NODE_TYPES.FunctionDeclaration) {
        const functionType = services.getContextualType(functionNode);

        if (functionType) {
          return tsutils
            .unionConstituents(functionType)
            .some(isFunctionReturnTypeIncludesVoid);
        }
      }

      return false;
    }

Type Aliases

Options

type Options = [
  {
    ignoreArrowShorthand?: boolean;
    ignoreVoidOperator?: boolean;
    ignoreVoidReturningFunctions?: boolean;
  },
];

MessageId

type MessageId = | 'invalidVoidExpr'
  | 'invalidVoidExprArrow'
  | 'invalidVoidExprArrowWrapVoid'
  | 'invalidVoidExprReturn'
  | 'invalidVoidExprReturnLast'
  | 'invalidVoidExprReturnWrapVoid'
  | 'invalidVoidExprWrapVoid'
  | 'voidExprWrapVoid';

ReturnStatementWithArgument

type ReturnStatementWithArgument = MakeRequired<
      TSESTree.ReturnStatement,
      'argument'
    >;

InvalidAncestor

type InvalidAncestor = | Exclude<TSESTree.Node, TSESTree.ReturnStatement>
      | ReturnStatementWithArgument;

Generated by Syntax Scribe