📄 no-inferrable-types.ts¶
📊 Analysis Summary¶
| Metric | Count |
|---|---|
| 🔧 Functions | 9 |
| 📦 Imports | 6 |
| 📊 Variables & Constants | 6 |
| 📑 Type Aliases | 3 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 packages/eslint-plugin/src/rules/no-inferrable-types.ts
📦 Imports¶
| Name | Source |
|---|---|
TSESTree |
@typescript-eslint/utils |
AST_NODE_TYPES |
@typescript-eslint/utils |
createRule |
../util |
nullThrows |
../util |
NullThrowsReasons |
../util |
skipChainExpression |
../util |
Variables & Constants¶
| Name | Type | Kind | Value | Exported |
|---|---|---|---|---|
keywordMap |
{ [x: number]: string; } |
const | `{ | |
| [AST_NODE_TYPES.TSBigIntKeyword]: 'bigint', | ||||
| [AST_NODE_TYPES.TSBooleanKeyword]: 'boolean', | ||||
| [AST_NODE_TYPES.TSNullKeyword]: 'null', | ||||
| [AST_NODE_TYPES.TSNumberKeyword]: 'number', | ||||
| [AST_NODE_TYPES.TSStringKeyword]: 'string', | ||||
| [AST_NODE_TYPES.TSSymbolKeyword]: 'symbol', | ||||
| [AST_NODE_TYPES.TSUndefinedKeyword]: 'undefined', | ||||
| }` | ✗ | |||
unwrappedInit |
any |
const | `hasUnaryPrefix(init, '-') | |
| ? init.argument | ||||
| : init` | ✗ | |||
unwrappedInit |
any |
const | `hasUnaryPrefix(init, '+', '-') | |
| ? init.argument | ||||
| : init` | ✗ | |||
isRegExpLiteral |
boolean |
const | `init.type === AST_NODE_TYPES.Literal && | |
| init.value instanceof RegExp` | ✗ | |||
isRegExpNewCall |
boolean |
const | `init.type === AST_NODE_TYPES.NewExpression && | |
| init.callee.type === AST_NODE_TYPES.Identifier && | ||||
| init.callee.name === 'RegExp'` | ✗ | |||
type |
string |
const | `typeNode.typeAnnotation.type === AST_NODE_TYPES.TSTypeReference | |
| ? // TODO - if we add more references | ||||
| 'RegExp' | ||||
| : keywordMap[typeNode.typeAnnotation.type]` | ✗ |
Functions¶
isFunctionCall(init: TSESTree.Expression, callName: string): boolean¶
Code
- Parameters:
init: TSESTree.ExpressioncallName: string- Return Type:
boolean - Calls:
skipChainExpression (from ../util)
isLiteral(init: TSESTree.Expression, typeName: string): boolean¶
Code
- Parameters:
init: TSESTree.ExpressiontypeName: string- Return Type:
boolean
isIdentifier(init: TSESTree.Expression, names: string[]): boolean¶
Code
- Parameters:
init: TSESTree.Expressionnames: string[]- Return Type:
boolean - Calls:
names.includes
hasUnaryPrefix(init: TSESTree.Expression, operators: string[]): init is TSESTree.UnaryExpression¶
Code
- Parameters:
init: TSESTree.Expressionoperators: string[]- Return Type:
init is TSESTree.UnaryExpression - Calls:
operators.includes
isInferrable(annotation: TSESTree.TypeNode, init: TSESTree.Expression): annotation is Keywords¶
Code
function isInferrable(
annotation: TSESTree.TypeNode,
init: TSESTree.Expression,
): annotation is Keywords {
switch (annotation.type) {
case AST_NODE_TYPES.TSBigIntKeyword: {
// note that bigint cannot have + prefixed to it
const unwrappedInit = hasUnaryPrefix(init, '-')
? init.argument
: init;
return (
isFunctionCall(unwrappedInit, 'BigInt') ||
unwrappedInit.type === AST_NODE_TYPES.Literal
);
}
case AST_NODE_TYPES.TSBooleanKeyword:
return (
hasUnaryPrefix(init, '!') ||
isFunctionCall(init, 'Boolean') ||
isLiteral(init, 'boolean')
);
case AST_NODE_TYPES.TSNumberKeyword: {
const unwrappedInit = hasUnaryPrefix(init, '+', '-')
? init.argument
: init;
return (
isIdentifier(unwrappedInit, 'Infinity', 'NaN') ||
isFunctionCall(unwrappedInit, 'Number') ||
isLiteral(unwrappedInit, 'number')
);
}
case AST_NODE_TYPES.TSNullKeyword:
return init.type === AST_NODE_TYPES.Literal && init.value == null;
case AST_NODE_TYPES.TSStringKeyword:
return (
isFunctionCall(init, 'String') ||
isLiteral(init, 'string') ||
init.type === AST_NODE_TYPES.TemplateLiteral
);
case AST_NODE_TYPES.TSSymbolKeyword:
return isFunctionCall(init, 'Symbol');
case AST_NODE_TYPES.TSTypeReference: {
if (
annotation.typeName.type === AST_NODE_TYPES.Identifier &&
annotation.typeName.name === 'RegExp'
) {
const isRegExpLiteral =
init.type === AST_NODE_TYPES.Literal &&
init.value instanceof RegExp;
const isRegExpNewCall =
init.type === AST_NODE_TYPES.NewExpression &&
init.callee.type === AST_NODE_TYPES.Identifier &&
init.callee.name === 'RegExp';
const isRegExpCall = isFunctionCall(init, 'RegExp');
return isRegExpLiteral || isRegExpCall || isRegExpNewCall;
}
return false;
}
case AST_NODE_TYPES.TSUndefinedKeyword:
return (
hasUnaryPrefix(init, 'void') || isIdentifier(init, 'undefined')
);
}
return false;
}
-
JSDoc:
-
Parameters:
annotation: TSESTree.TypeNodeinit: TSESTree.Expression- Return Type:
annotation is Keywords - Calls:
hasUnaryPrefixisFunctionCallisLiteralisIdentifier- Internal Comments:
`reportInferrableType(node: | TSESTree.AccessorProperty¶
| TSESTree.Parameter
| TSESTree.PropertyDefinition
| TSESTree.VariableDeclarator, typeNode: TSESTree.TSTypeAnnotation | undefined, initNode: TSESTree.Expression | null | undefined): void`
Code
function reportInferrableType(
node:
| TSESTree.AccessorProperty
| TSESTree.Parameter
| TSESTree.PropertyDefinition
| TSESTree.VariableDeclarator,
typeNode: TSESTree.TSTypeAnnotation | undefined,
initNode: TSESTree.Expression | null | undefined,
): void {
if (!typeNode || !initNode) {
return;
}
if (!isInferrable(typeNode.typeAnnotation, initNode)) {
return;
}
const type =
typeNode.typeAnnotation.type === AST_NODE_TYPES.TSTypeReference
? // TODO - if we add more references
'RegExp'
: keywordMap[typeNode.typeAnnotation.type];
context.report({
node,
messageId: 'noInferrableType',
data: {
type,
},
*fix(fixer) {
if (
(node.type === AST_NODE_TYPES.AssignmentPattern &&
node.left.optional) ||
(node.type === AST_NODE_TYPES.PropertyDefinition && node.definite)
) {
yield fixer.remove(
nullThrows(
context.sourceCode.getTokenBefore(typeNode),
NullThrowsReasons.MissingToken('token before', 'type node'),
),
);
}
yield fixer.remove(typeNode);
},
});
}
-
JSDoc:
-
Parameters:
node: | TSESTree.AccessorProperty | TSESTree.Parameter | TSESTree.PropertyDefinition | TSESTree.VariableDeclaratortypeNode: TSESTree.TSTypeAnnotation | undefinedinitNode: TSESTree.Expression | null | undefined- Return Type:
void - Calls:
isInferrablecontext.reportfixer.removenullThrows (from ../util)context.sourceCode.getTokenBeforeNullThrowsReasons.MissingToken
inferrableVariableVisitor(node: TSESTree.VariableDeclarator): void¶
Code
- Parameters:
node: TSESTree.VariableDeclarator- Return Type:
void - Calls:
reportInferrableType
`inferrableParameterVisitor(node: | TSESTree.ArrowFunctionExpression¶
| TSESTree.FunctionDeclaration
| TSESTree.FunctionExpression): void`
Code
function inferrableParameterVisitor(
node:
| TSESTree.ArrowFunctionExpression
| TSESTree.FunctionDeclaration
| TSESTree.FunctionExpression,
): void {
if (ignoreParameters) {
return;
}
node.params.forEach(param => {
if (param.type === AST_NODE_TYPES.TSParameterProperty) {
param = param.parameter;
}
if (param.type === AST_NODE_TYPES.AssignmentPattern) {
reportInferrableType(param, param.left.typeAnnotation, param.right);
}
});
}
- Parameters:
node: | TSESTree.ArrowFunctionExpression | TSESTree.FunctionDeclaration | TSESTree.FunctionExpression- Return Type:
void - Calls:
node.params.forEachreportInferrableType
inferrablePropertyVisitor(node: TSESTree.AccessorProperty | TSESTree.PropertyDefinition): void¶
Code
function inferrablePropertyVisitor(
node: TSESTree.AccessorProperty | TSESTree.PropertyDefinition,
): void {
// We ignore `readonly` because of Microsoft/TypeScript#14416
// Essentially a readonly property without a type
// will result in its value being the type, leading to
// compile errors if the type is stripped.
if (ignoreProperties || node.readonly || node.optional) {
return;
}
reportInferrableType(node, node.typeAnnotation, node.value);
}
- Parameters:
node: TSESTree.AccessorProperty | TSESTree.PropertyDefinition- Return Type:
void - Calls:
reportInferrableType- Internal Comments:
Type Aliases¶
Options¶
MessageIds¶
Keywords¶
type Keywords = | TSESTree.TSBigIntKeyword
| TSESTree.TSBooleanKeyword
| TSESTree.TSNullKeyword
| TSESTree.TSNumberKeyword
| TSESTree.TSStringKeyword
| TSESTree.TSSymbolKeyword
| TSESTree.TSTypeReference
| TSESTree.TSUndefinedKeyword;