Skip to content

⬅️ Back to Table of Contents

πŸ“„ prefer-reduce-type-parameter

πŸ“Š Analysis Summary

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

πŸ“š Table of Contents

πŸ› οΈ File Location:

πŸ“‚ packages/eslint-plugin/src/rules/prefer-reduce-type-parameter.ts

πŸ“€ Default Export

export default createRule({ ... })
Property Value
name 'prefer-reduce-type-parameter'
meta.type 'problem'
meta.docs.description 'Enforce using type parameter when calling Array#reduce instead of using a type assertion'
meta.docs.recommended 'strict'
meta.docs.requiresTypeChecking true
meta.fixable 'code'
meta.messages.preferTypeParameter 'Unnecessary assertion: Array#reduce accepts a type parameter for the default value.'
meta.schema []
defaultOptions []

Entry point: create β€” documented under Functions.


πŸ“¦ Imports

Name Source
TSESTree @typescript-eslint/utils
createRule ../util
getConstrainedTypeAtLocation ../util
getParserServices ../util
isStaticMemberAccessOfValue ../util
isTypeAssertion ../util

Functions

create(context: any): { 'CallExpression > MemberExpression.callee'(callee: Member…

Parameters:

  • context any

Returns: { 'CallExpression > MemberExpression.callee'(callee: MemberExpressionWithCallExpressionParent): void; }

Calls:

  • getParserServices (from ../util)
  • services.program.getTypeChecker
  • tsutils .unionConstituents(type) .every
  • tsutils .intersectionConstituents(unionPart) .every
  • checker.isArrayType
  • checker.isTupleType
  • isStaticMemberAccessOfValue (from ../util)
  • isTypeAssertion (from ../util)
  • services.getTypeAtLocation
  • checker.isTypeAssignableTo
  • getConstrainedTypeAtLocation (from ../util)
  • isArrayType
  • context.report
  • fixer.removeRange
  • fixes.push
  • fixer.insertTextAfter
  • context.sourceCode.getText

Internal Comments:

// don't report this if the resulting fix will be a type error
// Get the symbol of the `reduce` method. (x2)
// Check the owner type of the `reduce` method.

Code
create(context) {
    const services = getParserServices(context);
    const checker = services.program.getTypeChecker();

    function isArrayType(type: ts.Type): boolean {
      return tsutils
        .unionConstituents(type)
        .every(unionPart =>
          tsutils
            .intersectionConstituents(unionPart)
            .every(t => checker.isArrayType(t) || checker.isTupleType(t)),
        );
    }

    return {
      'CallExpression > MemberExpression.callee'(
        callee: MemberExpressionWithCallExpressionParent,
      ): void {
        if (!isStaticMemberAccessOfValue(callee, context, 'reduce')) {
          return;
        }

        const [, secondArg] = callee.parent.arguments;

        if (callee.parent.arguments.length < 2) {
          return;
        }

        if (isTypeAssertion(secondArg)) {
          const initializerType = services.getTypeAtLocation(
            secondArg.expression,
          );

          const assertedType = services.getTypeAtLocation(
            secondArg.typeAnnotation,
          );

          const isAssertionNecessary = !checker.isTypeAssignableTo(
            initializerType,
            assertedType,
          );

          // don't report this if the resulting fix will be a type error
          if (isAssertionNecessary) {
            return;
          }
        } else {
          return;
        }

        // Get the symbol of the `reduce` method.
        const calleeObjType = getConstrainedTypeAtLocation(
          services,
          callee.object,
        );

        // Check the owner type of the `reduce` method.
        if (isArrayType(calleeObjType)) {
          context.report({
            node: secondArg,
            messageId: 'preferTypeParameter',
            fix: fixer => {
              const fixes = [
                fixer.removeRange([
                  secondArg.range[0],
                  secondArg.expression.range[0],
                ]),
                fixer.removeRange([
                  secondArg.expression.range[1],
                  secondArg.range[1],
                ]),
              ];

              if (!callee.parent.typeArguments) {
                fixes.push(
                  fixer.insertTextAfter(
                    callee,
                    `<${context.sourceCode.getText(secondArg.typeAnnotation)}>`,
                  ),
                );
              }

              return fixes;
            },
          });

          return;
        }
      },
    };
  }

Internal helpers

Declared inside another function in this file.

isArrayType(type: ts.Type): boolean

Parameters:

  • type ts.Type

Returns: boolean

Calls:

  • tsutils .unionConstituents(type) .every
  • tsutils .intersectionConstituents(unionPart) .every
  • checker.isArrayType
  • checker.isTupleType
Code
function isArrayType(type: ts.Type): boolean {
      return tsutils
        .unionConstituents(type)
        .every(unionPart =>
          tsutils
            .intersectionConstituents(unionPart)
            .every(t => checker.isArrayType(t) || checker.isTupleType(t)),
        );
    }

fix(fixer: any): any[]

Parameters:

  • fixer any

Returns: any[]

Calls:

  • fixer.removeRange
  • fixes.push
  • fixer.insertTextAfter
  • context.sourceCode.getText
Code
fixer => {
              const fixes = [
                fixer.removeRange([
                  secondArg.range[0],
                  secondArg.expression.range[0],
                ]),
                fixer.removeRange([
                  secondArg.expression.range[1],
                  secondArg.range[1],
                ]),
              ];

              if (!callee.parent.typeArguments) {
                fixes.push(
                  fixer.insertTextAfter(
                    callee,
                    `<${context.sourceCode.getText(secondArg.typeAnnotation)}>`,
                  ),
                );
              }

              return fixes;
            }

Type Aliases

MemberExpressionWithCallExpressionParent

type MemberExpressionWithCallExpressionParent = {
  parent: TSESTree.CallExpression;
} & TSESTree.MemberExpression;

Generated by Syntax Scribe