UNPKG

4.62 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5}) : (function(o, m, k, k2) {
6 if (k2 === undefined) k2 = k;
7 o[k2] = m[k];
8}));
9var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10 Object.defineProperty(o, "default", { enumerable: true, value: v });
11}) : function(o, v) {
12 o["default"] = v;
13});
14var __importStar = (this && this.__importStar) || function (mod) {
15 if (mod && mod.__esModule) return mod;
16 var result = {};
17 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18 __setModuleDefault(result, mod);
19 return result;
20};
21Object.defineProperty(exports, "__esModule", { value: true });
22const utils_1 = require("@typescript-eslint/utils");
23const scope_manager_1 = require("@typescript-eslint/scope-manager");
24const util = __importStar(require("../util"));
25function hasAssignmentBeforeNode(variable, node) {
26 return (variable.references.some(ref => ref.isWrite() && ref.identifier.range[1] < node.range[1]) ||
27 variable.defs.some(def => isDefinitionWithAssignment(def) && def.node.range[1] < node.range[1]));
28}
29function isDefinitionWithAssignment(definition) {
30 if (definition.type !== scope_manager_1.DefinitionType.Variable) {
31 return false;
32 }
33 const variableDeclarator = definition.node;
34 return (variableDeclarator.definite === true || variableDeclarator.init !== null);
35}
36exports.default = util.createRule({
37 name: 'no-non-null-asserted-nullish-coalescing',
38 meta: {
39 type: 'problem',
40 docs: {
41 description: 'Disallows using a non-null assertion in the left operand of the nullish coalescing operator',
42 recommended: false,
43 },
44 messages: {
45 noNonNullAssertedNullishCoalescing: 'The nullish coalescing operator is designed to handle undefined and null - using a non-null assertion is not needed.',
46 suggestRemovingNonNull: 'Remove the non-null assertion.',
47 },
48 schema: [],
49 hasSuggestions: true,
50 },
51 defaultOptions: [],
52 create(context) {
53 return {
54 'LogicalExpression[operator = "??"] > TSNonNullExpression.left'(node) {
55 if (node.expression.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier) {
56 const scope = context.getScope();
57 const identifier = node.expression;
58 const variable = utils_1.ASTUtils.findVariable(scope, identifier.name);
59 if (variable && !hasAssignmentBeforeNode(variable, node)) {
60 return;
61 }
62 }
63 const sourceCode = context.getSourceCode();
64 context.report({
65 node,
66 messageId: 'noNonNullAssertedNullishCoalescing',
67 /*
68 Use a suggestion instead of a fixer, because this can break type checks.
69 The resulting type of the nullish coalesce is only influenced by the right operand if the left operand can be `null` or `undefined`.
70 After removing the non-null assertion the type of the left operand might contain `null` or `undefined` and then the type of the right operand
71 might change the resulting type of the nullish coalesce.
72 See the following example:
73
74 function test(x?: string): string {
75 const bar = x! ?? false; // type analysis reports `bar` has type `string`
76 // x ?? false; // type analysis reports `bar` has type `string | false`
77 return bar;
78 }
79 */
80 suggest: [
81 {
82 messageId: 'suggestRemovingNonNull',
83 fix(fixer) {
84 const exclamationMark = util.nullThrows(sourceCode.getLastToken(node, utils_1.ASTUtils.isNonNullAssertionPunctuator), util.NullThrowsReasons.MissingToken('!', 'Non-null Assertion'));
85 return fixer.remove(exclamationMark);
86 },
87 },
88 ],
89 });
90 },
91 };
92 },
93});
94//# sourceMappingURL=no-non-null-asserted-nullish-coalescing.js.map
\No newline at end of file