Skip to content

⬅️ Back to Table of Contents

📄 prefer-promise-reject-errors

📊 Analysis Summary

Metric Count
🔧 Functions 3
📦 Imports 17
📑 Type Aliases 2

📚 Table of Contents

🛠️ File Location:

📂 packages/eslint-plugin/src/rules/prefer-promise-reject-errors.ts

📤 Default Export

export default createRule<Options, MessageIds>({ ... })
Property Value
name 'prefer-promise-reject-errors'
meta.type 'suggestion'
meta.docs.description 'Require using Error objects as Promise rejection reasons'
meta.docs.extendsBaseRule true
meta.docs.recommended 'recommended'
meta.docs.requiresTypeChecking true
meta.messages.rejectAnError 'Expected the Promise rejection reason to be an Error.'
meta.schema [ { type: 'object', additionalProperties: false, properties: { allow: { ...typeOrValueSpecifiersSchema, description: ...
defaultOptions [ { allow: [], allowEmptyReject: false, allowThrowingAny: false, allowThrowingUnknown: false, }, ]

Entry point: create — documented under Functions.


📦 Imports

Name Source
TSESTree @typescript-eslint/utils
AST_NODE_TYPES @typescript-eslint/utils
TypeOrValueSpecifier ../util
createRule ../util
getParserServices ../util
isErrorLike ../util
isTypeAnyType ../util
isTypeUnknownType ../util
isFunction ../util
isIdentifier ../util
isPromiseConstructorLike ../util
isPromiseLike ../util
isReadonlyErrorLike ../util
isStaticMemberAccessOfValue ../util
skipChainExpression ../util
typeMatchesSomeSpecifier ../util
typeOrValueSpecifiersSchema ../util

Functions

create(context: any, [options]: any): { CallExpression(node: any): void; NewExpression(node: any)…

Parameters:

  • context any
  • [options] any

Returns: { CallExpression(node: any): void; NewExpression(node: any): void; }

Calls:

  • getParserServices (from ../util)
  • callExpression.arguments.at
  • services.getTypeAtLocation
  • typeMatchesSomeSpecifier (from ../util)
  • isTypeAnyType (from ../util)
  • isTypeUnknownType (from ../util)
  • isErrorLike (from ../util)
  • isReadonlyErrorLike (from ../util)
  • context.report
  • isPromiseConstructorLike (from ../util)
  • isPromiseLike (from ../util)
  • skipChainExpression (from ../util)
  • isStaticMemberAccessOfValue (from ../util)
  • typeAtLocationIsLikePromise
  • checkRejectCall
  • node.arguments.at
  • isFunction (from ../util)
  • executor.params.at
  • isIdentifier (from ../util)
  • context.sourceCode .getDeclaredVariables(executor) .find
  • variable.identifiers.includes
  • rejectVariable.references.forEach

Internal Comments:

// reject param is always present in variables declared by executor (x2)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion (x2)

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

    function checkRejectCall(callExpression: TSESTree.CallExpression): void {
      const argument = callExpression.arguments.at(0);
      if (argument) {
        const type = services.getTypeAtLocation(argument);

        if (typeMatchesSomeSpecifier(type, options.allow, services.program)) {
          return;
        }

        if (options.allowThrowingAny && isTypeAnyType(type)) {
          return;
        }

        if (options.allowThrowingUnknown && isTypeUnknownType(type)) {
          return;
        }

        if (
          isErrorLike(services.program, type) ||
          isReadonlyErrorLike(services.program, type)
        ) {
          return;
        }
      } else if (options.allowEmptyReject) {
        return;
      }

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

    function typeAtLocationIsLikePromise(node: TSESTree.Node): boolean {
      const type = services.getTypeAtLocation(node);
      return (
        isPromiseConstructorLike(services.program, type) ||
        isPromiseLike(services.program, type)
      );
    }

    return {
      CallExpression(node): void {
        const callee = skipChainExpression(node.callee);

        if (callee.type !== AST_NODE_TYPES.MemberExpression) {
          return;
        }

        if (
          !isStaticMemberAccessOfValue(callee, context, 'reject') ||
          !typeAtLocationIsLikePromise(callee.object)
        ) {
          return;
        }

        checkRejectCall(node);
      },
      NewExpression(node): void {
        const callee = skipChainExpression(node.callee);
        if (
          !isPromiseConstructorLike(
            services.program,
            services.getTypeAtLocation(callee),
          )
        ) {
          return;
        }

        const executor = node.arguments.at(0);
        if (!executor || !isFunction(executor)) {
          return;
        }
        const rejectParamNode = executor.params.at(1);
        if (!rejectParamNode || !isIdentifier(rejectParamNode)) {
          return;
        }

        // reject param is always present in variables declared by executor
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        const rejectVariable = context.sourceCode
          .getDeclaredVariables(executor)
          .find(variable => variable.identifiers.includes(rejectParamNode))!;

        rejectVariable.references.forEach(ref => {
          if (
            ref.identifier.parent.type !== AST_NODE_TYPES.CallExpression ||
            ref.identifier !== ref.identifier.parent.callee
          ) {
            return;
          }

          checkRejectCall(ref.identifier.parent);
        });
      },
    };
  }

Internal helpers

Declared inside another function in this file.

checkRejectCall(callExpression: TSESTree.CallExpression): void

Parameters:

  • callExpression TSESTree.CallExpression

Returns: void

Calls:

  • callExpression.arguments.at
  • services.getTypeAtLocation
  • typeMatchesSomeSpecifier (from ../util)
  • isTypeAnyType (from ../util)
  • isTypeUnknownType (from ../util)
  • isErrorLike (from ../util)
  • isReadonlyErrorLike (from ../util)
  • context.report
Code
function checkRejectCall(callExpression: TSESTree.CallExpression): void {
      const argument = callExpression.arguments.at(0);
      if (argument) {
        const type = services.getTypeAtLocation(argument);

        if (typeMatchesSomeSpecifier(type, options.allow, services.program)) {
          return;
        }

        if (options.allowThrowingAny && isTypeAnyType(type)) {
          return;
        }

        if (options.allowThrowingUnknown && isTypeUnknownType(type)) {
          return;
        }

        if (
          isErrorLike(services.program, type) ||
          isReadonlyErrorLike(services.program, type)
        ) {
          return;
        }
      } else if (options.allowEmptyReject) {
        return;
      }

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

typeAtLocationIsLikePromise(node: TSESTree.Node): boolean

Parameters:

  • node TSESTree.Node

Returns: boolean

Calls:

  • services.getTypeAtLocation
  • isPromiseConstructorLike (from ../util)
  • isPromiseLike (from ../util)
Code
function typeAtLocationIsLikePromise(node: TSESTree.Node): boolean {
      const type = services.getTypeAtLocation(node);
      return (
        isPromiseConstructorLike(services.program, type) ||
        isPromiseLike(services.program, type)
      );
    }

Type Aliases

MessageIds

type MessageIds = 'rejectAnError';

Options

type Options = [
  {
    allow?: TypeOrValueSpecifier[];
    allowEmptyReject?: boolean;
    allowThrowingAny?: boolean;
    allowThrowingUnknown?: boolean;
  },
];

Generated by Syntax Scribe