📄 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.Expression
callName: string
- Return Type:
boolean
- Calls:
skipChainExpression (from ../util)
isLiteral(init: TSESTree.Expression, typeName: string): boolean
¶
Code
- Parameters:
init: TSESTree.Expression
typeName: string
- Return Type:
boolean
isIdentifier(init: TSESTree.Expression, names: string[]): boolean
¶
Code
- Parameters:
init: TSESTree.Expression
names: string[]
- Return Type:
boolean
- Calls:
names.includes
hasUnaryPrefix(init: TSESTree.Expression, operators: string[]): init is TSESTree.UnaryExpression
¶
Code
- Parameters:
init: TSESTree.Expression
operators: 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.TypeNode
init: TSESTree.Expression
- Return Type:
annotation is Keywords
- Calls:
hasUnaryPrefix
isFunctionCall
isLiteral
isIdentifier
- 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.VariableDeclarator
typeNode: TSESTree.TSTypeAnnotation | undefined
initNode: TSESTree.Expression | null | undefined
- Return Type:
void
- Calls:
isInferrable
context.report
fixer.remove
nullThrows (from ../util)
context.sourceCode.getTokenBefore
NullThrowsReasons.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.forEach
reportInferrableType
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;