| "use strict"; |
| var __importStar = (this && this.__importStar) || function (mod) { |
| if (mod && mod.__esModule) return mod; |
| var result = {}; |
| if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; |
| result["default"] = mod; |
| return result; |
| }; |
| Object.defineProperty(exports, "__esModule", { value: true }); |
| const experimental_utils_1 = require("@typescript-eslint/experimental-utils"); |
| const util = __importStar(require("../util")); |
| exports.default = util.createRule({ |
| name: 'no-inferrable-types', |
| meta: { |
| type: 'suggestion', |
| docs: { |
| description: 'Disallows explicit type declarations for variables or parameters initialized to a number, string, or boolean', |
| category: 'Best Practices', |
| recommended: 'error', |
| }, |
| fixable: 'code', |
| messages: { |
| noInferrableType: 'Type {{type}} trivially inferred from a {{type}} literal, remove type annotation.', |
| }, |
| schema: [ |
| { |
| type: 'object', |
| properties: { |
| ignoreParameters: { |
| type: 'boolean', |
| }, |
| ignoreProperties: { |
| type: 'boolean', |
| }, |
| }, |
| additionalProperties: false, |
| }, |
| ], |
| }, |
| defaultOptions: [ |
| { |
| ignoreParameters: true, |
| ignoreProperties: true, |
| }, |
| ], |
| create(context, [{ ignoreParameters, ignoreProperties }]) { |
| function isFunctionCall(init, callName) { |
| return (init.type === experimental_utils_1.AST_NODE_TYPES.CallExpression && |
| init.callee.type === experimental_utils_1.AST_NODE_TYPES.Identifier && |
| init.callee.name === callName); |
| } |
| function isLiteral(init, typeName) { |
| return (init.type === experimental_utils_1.AST_NODE_TYPES.Literal && typeof init.value === typeName); |
| } |
| function isIdentifier(init, ...names) { |
| return (init.type === experimental_utils_1.AST_NODE_TYPES.Identifier && names.includes(init.name)); |
| } |
| function hasUnaryPrefix(init, ...operators) { |
| return (init.type === experimental_utils_1.AST_NODE_TYPES.UnaryExpression && |
| operators.includes(init.operator)); |
| } |
| const keywordMap = { |
| [experimental_utils_1.AST_NODE_TYPES.TSBigIntKeyword]: 'bigint', |
| [experimental_utils_1.AST_NODE_TYPES.TSBooleanKeyword]: 'boolean', |
| [experimental_utils_1.AST_NODE_TYPES.TSNumberKeyword]: 'number', |
| [experimental_utils_1.AST_NODE_TYPES.TSNullKeyword]: 'null', |
| [experimental_utils_1.AST_NODE_TYPES.TSStringKeyword]: 'string', |
| [experimental_utils_1.AST_NODE_TYPES.TSSymbolKeyword]: 'symbol', |
| [experimental_utils_1.AST_NODE_TYPES.TSUndefinedKeyword]: 'undefined', |
| }; |
| /** |
| * Returns whether a node has an inferrable value or not |
| */ |
| function isInferrable(annotation, init) { |
| switch (annotation.type) { |
| case experimental_utils_1.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 === experimental_utils_1.AST_NODE_TYPES.BigIntLiteral); |
| } |
| case experimental_utils_1.AST_NODE_TYPES.TSBooleanKeyword: |
| return (hasUnaryPrefix(init, '!') || |
| isFunctionCall(init, 'Boolean') || |
| isLiteral(init, 'boolean')); |
| case experimental_utils_1.AST_NODE_TYPES.TSNumberKeyword: { |
| const unwrappedInit = hasUnaryPrefix(init, '+', '-') |
| ? init.argument |
| : init; |
| return (isIdentifier(unwrappedInit, 'Infinity', 'NaN') || |
| isFunctionCall(unwrappedInit, 'Number') || |
| isLiteral(unwrappedInit, 'number')); |
| } |
| case experimental_utils_1.AST_NODE_TYPES.TSNullKeyword: |
| return init.type === experimental_utils_1.AST_NODE_TYPES.Literal && init.value === null; |
| case experimental_utils_1.AST_NODE_TYPES.TSStringKeyword: |
| return (isFunctionCall(init, 'String') || |
| isLiteral(init, 'string') || |
| init.type === experimental_utils_1.AST_NODE_TYPES.TemplateLiteral); |
| case experimental_utils_1.AST_NODE_TYPES.TSSymbolKeyword: |
| return isFunctionCall(init, 'Symbol'); |
| case experimental_utils_1.AST_NODE_TYPES.TSTypeReference: { |
| if (annotation.typeName.type === experimental_utils_1.AST_NODE_TYPES.Identifier && |
| annotation.typeName.name === 'RegExp') { |
| const isRegExpLiteral = init.type === experimental_utils_1.AST_NODE_TYPES.Literal && |
| init.value instanceof RegExp; |
| const isRegExpNewCall = init.type === experimental_utils_1.AST_NODE_TYPES.NewExpression && |
| init.callee.type === 'Identifier' && |
| init.callee.name === 'RegExp'; |
| const isRegExpCall = isFunctionCall(init, 'RegExp'); |
| return isRegExpLiteral || isRegExpCall || isRegExpNewCall; |
| } |
| return false; |
| } |
| case experimental_utils_1.AST_NODE_TYPES.TSUndefinedKeyword: |
| return (hasUnaryPrefix(init, 'void') || isIdentifier(init, 'undefined')); |
| } |
| return false; |
| } |
| /** |
| * Reports an inferrable type declaration, if any |
| */ |
| function reportInferrableType(node, typeNode, initNode) { |
| if (!typeNode || !initNode || !typeNode.typeAnnotation) { |
| return; |
| } |
| if (!isInferrable(typeNode.typeAnnotation, initNode)) { |
| return; |
| } |
| const type = typeNode.typeAnnotation.type === experimental_utils_1.AST_NODE_TYPES.TSTypeReference |
| ? // TODO - if we add more references |
| 'RegExp' |
| : keywordMap[typeNode.typeAnnotation.type]; |
| context.report({ |
| node, |
| messageId: 'noInferrableType', |
| data: { |
| type, |
| }, |
| fix: fixer => fixer.remove(typeNode), |
| }); |
| } |
| function inferrableVariableVisitor(node) { |
| if (!node.id) { |
| return; |
| } |
| reportInferrableType(node, node.id.typeAnnotation, node.init); |
| } |
| function inferrableParameterVisitor(node) { |
| if (ignoreParameters || !node.params) { |
| return; |
| } |
| node.params.filter(param => param.type === experimental_utils_1.AST_NODE_TYPES.AssignmentPattern && |
| param.left && |
| param.right).forEach(param => { |
| reportInferrableType(param, param.left.typeAnnotation, param.right); |
| }); |
| } |
| function inferrablePropertyVisitor(node) { |
| // 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) { |
| return; |
| } |
| reportInferrableType(node, node.typeAnnotation, node.value); |
| } |
| return { |
| VariableDeclarator: inferrableVariableVisitor, |
| FunctionExpression: inferrableParameterVisitor, |
| FunctionDeclaration: inferrableParameterVisitor, |
| ArrowFunctionExpression: inferrableParameterVisitor, |
| ClassProperty: inferrablePropertyVisitor, |
| }; |
| }, |
| }); |
| //# sourceMappingURL=no-inferrable-types.js.map |