📄 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¶
| 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:
contextany[options]any
Returns: { TSArrayType(node: any): void; TSTypeReference(node: any): void; }
Calls:
isSimpleTypecontext.sourceCode.getTextcontext.reportgetMessageTypefixer.replaceTextRangecontext.sourceCode.getScopescope.set.hastypeNeedsParenthesesisParenthesized (from ../util)
Internal Comments:
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:
nodeany: the node to be evaluated.
Raw JSDoc
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:
nodeany: 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:
nodeany: the node to be evaluated.
Calls:
isSimpleTypecontext.sourceCode.getText
Code
Type Aliases¶
OptionString¶
Options¶
MessageIds¶
type MessageIds = | 'errorStringArray'
| 'errorStringArrayReadonly'
| 'errorStringArraySimple'
| 'errorStringArraySimpleReadonly'
| 'errorStringGeneric'
| 'errorStringGenericSimple';
Generated by Syntax Scribe