Skip to content

⬅️ Back to Table of Contents

πŸ“„ no-unsafe-enum-comparison

πŸ“Š Analysis Summary

Metric Count
πŸ”§ Functions 1
πŸ“¦ Imports 8

πŸ“š Table of Contents

πŸ› οΈ File Location:

πŸ“‚ packages/eslint-plugin/src/rules/no-unsafe-enum-comparison.ts

πŸ“€ Default Export

export default createRule({ ... })
Property Value
name 'no-unsafe-enum-comparison'
meta.type 'suggestion'
meta.docs.description 'Disallow comparing an enum value with a non-enum value'
meta.docs.recommended 'recommended'
meta.docs.requiresTypeChecking true
meta.hasSuggestions true
meta.messages.mismatchedCase 'The case statement does not have a shared enum type with the switch predicate.'
meta.messages.mismatchedCondition 'The two values in this comparison do not have a shared enum type.'
meta.messages.replaceValueWithEnum 'Replace with an enum value comparison.'
meta.schema []
defaultOptions []

Entry point: create β€” documented under Functions.


πŸ“¦ Imports

Name Source
TSESLint @typescript-eslint/utils
TSESTree @typescript-eslint/utils
createRule ../util
getParserServices ../util
getStaticValue ../util
getEnumKeyForLiteral ./enum-utils/shared
getEnumLiterals ./enum-utils/shared
isMismatchedEnumComparisonTypes ./enum-utils/shared

Functions

create(context: any): { 'BinaryExpression[operator=/^[<>!=]?={0,2}$/]'(node: TSES…

Parameters:

  • context any

Returns: { 'BinaryExpression[operator=/^[<>!=]?={0,2}$/]'(node: TSESTree.BinaryExpression): void; SwitchCase(node: any): void; }

Calls:

  • getParserServices (from ../util)
  • parserServices.program.getTypeChecker
  • parserServices.getTypeAtLocation
  • isMismatchedEnumComparisonTypes (from ./enum-utils/shared)
  • context.report
  • getEnumKeyForLiteral (from ./enum-utils/shared)
  • getEnumLiterals (from ./enum-utils/shared)
  • getStaticValue (from ../util)
  • fixer.replaceText

Internal Comments:

// Replace the right side with an enum key if possible: (x2)
// (x4)
// ```ts (x4)
// Fruit.Apple === 'apple'; // Fruit.Apple === Fruit.Apple (x2)
// ``` (x4)
// Replace the left side with an enum key if possible: (x2)
// declare const fruit: Fruit; (x2)
// 'apple' === Fruit.Apple; // Fruit.Apple === Fruit.Apple (x2)
// Ignore `default` cases.

Code
create(context) {
    const parserServices = getParserServices(context);
    const typeChecker = parserServices.program.getTypeChecker();

    return {
      'BinaryExpression[operator=/^[<>!=]?={0,2}$/]'(
        node: TSESTree.BinaryExpression,
      ): void {
        const leftType = parserServices.getTypeAtLocation(node.left);
        const rightType = parserServices.getTypeAtLocation(node.right);

        if (isMismatchedEnumComparisonTypes(typeChecker, leftType, rightType)) {
          context.report({
            node,
            messageId: 'mismatchedCondition',
            suggest: [
              {
                messageId: 'replaceValueWithEnum',
                fix(fixer): TSESLint.RuleFix | null {
                  // Replace the right side with an enum key if possible:
                  //
                  // ```ts
                  // Fruit.Apple === 'apple'; // Fruit.Apple === Fruit.Apple
                  // ```
                  const leftEnumKey = getEnumKeyForLiteral(
                    getEnumLiterals(leftType),
                    getStaticValue(node.right)?.value,
                  );

                  if (leftEnumKey) {
                    return fixer.replaceText(node.right, leftEnumKey);
                  }

                  // Replace the left side with an enum key if possible:
                  //
                  // ```ts
                  // declare const fruit: Fruit;
                  // 'apple' === Fruit.Apple; // Fruit.Apple === Fruit.Apple
                  // ```
                  const rightEnumKey = getEnumKeyForLiteral(
                    getEnumLiterals(rightType),
                    getStaticValue(node.left)?.value,
                  );

                  if (rightEnumKey) {
                    return fixer.replaceText(node.left, rightEnumKey);
                  }

                  return null;
                },
              },
            ],
          });
        }
      },

      SwitchCase(node): void {
        // Ignore `default` cases.
        if (node.test == null) {
          return;
        }

        const { parent } = node;

        const leftType = parserServices.getTypeAtLocation(parent.discriminant);
        const rightType = parserServices.getTypeAtLocation(node.test);

        if (isMismatchedEnumComparisonTypes(typeChecker, leftType, rightType)) {
          context.report({
            node,
            messageId: 'mismatchedCase',
          });
        }
      },
    };
  }

Generated by Syntax Scribe