Skip to content

⬅️ Back to Table of Contents

📄 array-type

📊 Analysis Summary

Metric Count
🔧 Functions 4
📦 Imports 4
📑 Type Aliases 3

📚 Table of Contents

🛠️ File Location:

📂 packages/eslint-plugin/src/rules/array-type.ts

📤 Default Export

export default createRule<Options, MessageIds>({ ... })
Property Value
name 'array-type'
meta.type 'suggestion'
meta.docs.description 'Require consistently using either T[] or Array<T> for arrays'
meta.docs.recommended 'stylistic'
meta.fixable 'code'
meta.messages.errorStringArray "Array type using '{{className}}<{{type}}>' is forbidden. Use '{{readonlyPrefix}}{{type}}[]' instead."
meta.messages.errorStringArrayReadonly "Array type using '{{className}}<{{type}}>' is forbidden. Use '{{readonlyPrefix}}{{type}}' instead."
meta.messages.errorStringArraySimple "Array type using '{{className}}<{{type}}>' is forbidden for simple types. Use '{{readonlyPrefix}}{{type}}[]' instead."
meta.messages.errorStringArraySimpleReadonly "Array type using '{{className}}<{{type}}>' is forbidden for simple types. Use '{{readonlyPrefix}}{{type}}' instead."
meta.messages.errorStringGeneric "Array type using '{{readonlyPrefix}}{{type}}[]' is forbidden. Use '{{className}}<{{type}}>' instead."
meta.messages.errorStringGenericSimple "Array type using '{{readonlyPrefix}}{{type}}[]' is forbidden for non-simple types. Use '{{className}}<{{type}}>' ins...
meta.schema [ { type: 'object', $defs: { arrayOption: { type: 'string', enum: ['array', 'generic', 'array-simple'], }, }, additio...
defaultOptions [ { default: 'array', }, ]

Entry point: create — documented under Functions.


📦 Imports

Name Source
TSESTree @typescript-eslint/utils
AST_NODE_TYPES @typescript-eslint/utils
createRule ../util
isParenthesized ../util

Functions

create(context: any, [options]: any): { TSArrayType(node: any): void; TSTypeReference(node: any):…

Parameters:

  • context any
  • [options] any

Returns: { TSArrayType(node: any): void; TSTypeReference(node: any): void; }

Calls:

  • isSimpleType
  • context.sourceCode.getText
  • context.report
  • getMessageType
  • fixer.replaceTextRange
  • context.sourceCode.getScope
  • scope.set.has
  • typeNeedsParentheses
  • isParenthesized (from ../util)

Internal Comments:

/**
     * @param node the node to be evaluated.
     */

Code
create(context, [options]) {
    const defaultOption = options.default;
    const readonlyOption = options.readonly ?? defaultOption;

    /**
     * @param node the node to be evaluated.
     */
    function getMessageType(node: TSESTree.Node): string {
      if (isSimpleType(node)) {
        return context.sourceCode.getText(node);
      }
      return 'T';
    }

    return {
      TSArrayType(node): void {
        const isReadonly =
          node.parent.type === AST_NODE_TYPES.TSTypeOperator &&
          node.parent.operator === 'readonly';

        const currentOption = isReadonly ? readonlyOption : defaultOption;

        if (
          currentOption === 'array' ||
          (currentOption === 'array-simple' && isSimpleType(node.elementType))
        ) {
          return;
        }

        const messageId =
          currentOption === 'generic'
            ? 'errorStringGeneric'
            : 'errorStringGenericSimple';
        const errorNode = isReadonly ? node.parent : node;

        context.report({
          node: errorNode,
          messageId,
          data: {
            type: getMessageType(node.elementType),
            className: isReadonly ? 'ReadonlyArray' : 'Array',
            readonlyPrefix: isReadonly ? 'readonly ' : '',
          },
          fix(fixer) {
            const typeNode = node.elementType;
            const arrayType = isReadonly ? 'ReadonlyArray' : 'Array';

            return [
              fixer.replaceTextRange(
                [errorNode.range[0], typeNode.range[0]],
                `${arrayType}<`,
              ),
              fixer.replaceTextRange(
                [typeNode.range[1], errorNode.range[1]],
                '>',
              ),
            ];
          },
        });
      },

      TSTypeReference(node): void {
        if (
          node.typeName.type !== AST_NODE_TYPES.Identifier ||
          !(
            node.typeName.name === 'Array' ||
            node.typeName.name === 'ReadonlyArray' ||
            node.typeName.name === 'Readonly'
          ) ||
          (node.typeName.name === 'Readonly' &&
            node.typeArguments?.params[0].type !== AST_NODE_TYPES.TSArrayType)
        ) {
          return;
        }

        for (
          let scope = context.sourceCode.getScope(node);
          scope.upper;
          scope = scope.upper
        ) {
          if (scope.set.has(node.typeName.name)) {
            return;
          }
        }

        const isReadonlyWithGenericArrayType =
          node.typeName.name === 'Readonly' &&
          node.typeArguments?.params[0].type === AST_NODE_TYPES.TSArrayType;
        const isReadonlyArrayType =
          node.typeName.name === 'ReadonlyArray' ||
          isReadonlyWithGenericArrayType;

        const currentOption = isReadonlyArrayType
          ? readonlyOption
          : defaultOption;

        if (currentOption === 'generic') {
          return;
        }

        const readonlyPrefix = isReadonlyArrayType ? 'readonly ' : '';
        const typeParams = node.typeArguments?.params;
        const messageId =
          currentOption === 'array'
            ? isReadonlyWithGenericArrayType
              ? 'errorStringArrayReadonly'
              : 'errorStringArray'
            : isReadonlyArrayType && node.typeName.name !== 'ReadonlyArray'
              ? 'errorStringArraySimpleReadonly'
              : 'errorStringArraySimple';

        if (!typeParams) {
          return;
        }

        if (
          typeParams.length !== 1 ||
          (currentOption === 'array-simple' && !isSimpleType(typeParams[0]))
        ) {
          return;
        }

        const type = typeParams[0];
        const typeParens = typeNeedsParentheses(type);
        const parentParens =
          readonlyPrefix &&
          node.parent.type === AST_NODE_TYPES.TSArrayType &&
          !isParenthesized(node.parent.elementType, context.sourceCode);

        const start = `${parentParens ? '(' : ''}${readonlyPrefix}${
          typeParens ? '(' : ''
        }`;
        const end = `${typeParens ? ')' : ''}${isReadonlyWithGenericArrayType ? '' : `[]`}${parentParens ? ')' : ''}`;
        context.report({
          node,
          messageId,
          data: {
            type: getMessageType(type),
            className: isReadonlyArrayType ? node.typeName.name : 'Array',
            readonlyPrefix,
          },
          fix(fixer) {
            return [
              fixer.replaceTextRange([node.range[0], type.range[0]], start),
              fixer.replaceTextRange([type.range[1], node.range[1]], end),
            ];
          },
        });
      },
    };
  }

isSimpleType(node: TSESTree.Node): boolean

Check whatever node can be considered as simple

Parameters:

  • node any: the node to be evaluated.
Raw JSDoc
/**
 * Check whatever node can be considered as simple
 * @param node the node to be evaluated.
 */

Calls:

  • isSimpleType
Code
function isSimpleType(node: TSESTree.Node): boolean {
  switch (node.type) {
    case AST_NODE_TYPES.Identifier:
    case AST_NODE_TYPES.TSAnyKeyword:
    case AST_NODE_TYPES.TSBooleanKeyword:
    case AST_NODE_TYPES.TSNeverKeyword:
    case AST_NODE_TYPES.TSNumberKeyword:
    case AST_NODE_TYPES.TSBigIntKeyword:
    case AST_NODE_TYPES.TSObjectKeyword:
    case AST_NODE_TYPES.TSStringKeyword:
    case AST_NODE_TYPES.TSSymbolKeyword:
    case AST_NODE_TYPES.TSUnknownKeyword:
    case AST_NODE_TYPES.TSVoidKeyword:
    case AST_NODE_TYPES.TSNullKeyword:
    case AST_NODE_TYPES.TSArrayType:
    case AST_NODE_TYPES.TSUndefinedKeyword:
    case AST_NODE_TYPES.TSThisType:
    case AST_NODE_TYPES.TSQualifiedName:
      return true;
    case AST_NODE_TYPES.TSTypeReference:
      if (
        node.typeName.type === AST_NODE_TYPES.Identifier &&
        node.typeName.name === 'Array'
      ) {
        if (!node.typeArguments) {
          return true;
        }
        if (node.typeArguments.params.length === 1) {
          return isSimpleType(node.typeArguments.params[0]);
        }
      } else {
        if (node.typeArguments) {
          return false;
        }
        return isSimpleType(node.typeName);
      }
      return false;
    default:
      return false;
  }
}

typeNeedsParentheses(node: TSESTree.Node): boolean

Check if node needs parentheses

Parameters:

  • node any: the node to be evaluated.
Raw JSDoc
/**
 * Check if node needs parentheses
 * @param node the node to be evaluated.
 */

Calls:

  • typeNeedsParentheses
Code
function typeNeedsParentheses(node: TSESTree.Node): boolean {
  switch (node.type) {
    case AST_NODE_TYPES.TSTypeReference:
      return typeNeedsParentheses(node.typeName);
    case AST_NODE_TYPES.TSUnionType:
    case AST_NODE_TYPES.TSFunctionType:
    case AST_NODE_TYPES.TSIntersectionType:
    case AST_NODE_TYPES.TSTypeOperator:
    case AST_NODE_TYPES.TSInferType:
    case AST_NODE_TYPES.TSConstructorType:
    case AST_NODE_TYPES.TSConditionalType:
      return true;
    case AST_NODE_TYPES.Identifier:
      return node.name === 'ReadonlyArray';
    default:
      return false;
  }
}

Internal helpers

Declared inside another function in this file.

getMessageType(node: TSESTree.Node): string

Parameters:

  • node any: the node to be evaluated.
Raw JSDoc
/**
     * @param node the node to be evaluated.
     */

Calls:

  • isSimpleType
  • context.sourceCode.getText
Code
function getMessageType(node: TSESTree.Node): string {
      if (isSimpleType(node)) {
        return context.sourceCode.getText(node);
      }
      return 'T';
    }

Type Aliases

OptionString

type OptionString = 'array' | 'array-simple' | 'generic';

Options

type Options = [
  {
    default: OptionString;
    readonly?: OptionString;
  },
];

MessageIds

type MessageIds = | 'errorStringArray'
  | 'errorStringArrayReadonly'
  | 'errorStringArraySimple'
  | 'errorStringArraySimpleReadonly'
  | 'errorStringGeneric'
  | 'errorStringGenericSimple';

Generated by Syntax Scribe