Skip to content

⬅️ Back to Table of Contents

📄 no-for-in-array

📊 Analysis Summary

Metric Count
🔧 Functions 4
📦 Imports 4

📚 Table of Contents

🛠️ File Location:

📂 packages/eslint-plugin/src/rules/no-for-in-array.ts

📤 Default Export

export default createRule({ ... })
Property Value
name 'no-for-in-array'
meta.type 'problem'
meta.docs.description 'Disallow iterating over an array with a for-in loop'
meta.docs.recommended 'recommended'
meta.docs.requiresTypeChecking true
meta.messages.forInViolation 'For-in loops over arrays skips holes, returns indices as strings, and may visit the prototype chain or other enumera...
meta.schema []
defaultOptions []

Entry point: create — documented under Functions.


📦 Imports

Name Source
createRule ../util
getConstrainedTypeAtLocation ../util
getParserServices ../util
getForStatementHeadLoc ../util/getForStatementHeadLoc

Functions

create(context: any): { ForInStatement(node: any): void; }

Parameters:

  • context any

Returns: { ForInStatement(node: any): void; }

Calls:

  • getParserServices (from ../util)
  • services.program.getTypeChecker
  • getConstrainedTypeAtLocation (from ../util)
  • isArrayLike
  • context.report
  • getForStatementHeadLoc (from ../util/getForStatementHeadLoc)
Code
create(context) {
    return {
      ForInStatement(node): void {
        const services = getParserServices(context);
        const checker = services.program.getTypeChecker();

        const type = getConstrainedTypeAtLocation(services, node.right);

        if (isArrayLike(checker, type)) {
          context.report({
            loc: getForStatementHeadLoc(context.sourceCode, node),
            messageId: 'forInViolation',
          });
        }
      },
    };
  }

isArrayLike(checker: ts.TypeChecker, type: ts.Type): boolean

Parameters:

  • checker ts.TypeChecker
  • type ts.Type

Returns: boolean

Calls:

  • isTypeRecurser
  • t.getNumberIndexType
  • hasArrayishLength
Code
function isArrayLike(checker: ts.TypeChecker, type: ts.Type): boolean {
  return isTypeRecurser(
    type,
    t => t.getNumberIndexType() != null && hasArrayishLength(checker, t),
  );
}

hasArrayishLength(checker: ts.TypeChecker, type: ts.Type): boolean

Parameters:

  • checker ts.TypeChecker
  • type ts.Type

Returns: boolean

Calls:

  • type.getProperty
  • tsutils.isTypeFlagSet
  • checker.getTypeOfSymbol
Code
function hasArrayishLength(checker: ts.TypeChecker, type: ts.Type): boolean {
  const lengthProperty = type.getProperty('length');

  if (lengthProperty == null) {
    return false;
  }

  return tsutils.isTypeFlagSet(
    checker.getTypeOfSymbol(lengthProperty),
    ts.TypeFlags.NumberLike,
  );
}

isTypeRecurser(type: ts.Type, predicate: (t: ts.Type) => boolean): boolean

Parameters:

  • type ts.Type
  • predicate (t: ts.Type) => boolean

Returns: boolean

Calls:

  • type.isUnionOrIntersection
  • type.types.some
  • isTypeRecurser
  • predicate
Code
function isTypeRecurser(
  type: ts.Type,
  predicate: (t: ts.Type) => boolean,
): boolean {
  if (type.isUnionOrIntersection()) {
    return type.types.some(t => isTypeRecurser(t, predicate));
  }

  return predicate(type);
}

Generated by Syntax Scribe