Skip to content

Commit cb22561

Browse files
authored
fix(eslint-plugin): [no-unnecessary-type-assertion] handle assignment (typescript-eslint#3133)
1 parent 3f9e9a1 commit cb22561

File tree

3 files changed

+67
-0
lines changed

3 files changed

+67
-0
lines changed

packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,26 @@ export default util.createRule<Options, MessageIds>({
135135

136136
return {
137137
TSNonNullExpression(node): void {
138+
if (
139+
node.parent?.type === AST_NODE_TYPES.AssignmentExpression &&
140+
node.parent?.operator === '=' &&
141+
node.parent.left === node
142+
) {
143+
context.report({
144+
node,
145+
messageId: 'contextuallyUnnecessary',
146+
fix(fixer) {
147+
return fixer.removeRange([
148+
node.expression.range[1],
149+
node.range[1],
150+
]);
151+
},
152+
});
153+
return;
154+
}
155+
138156
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
157+
139158
const type = util.getConstrainedTypeAtLocation(
140159
checker,
141160
originalNode.expression,

packages/eslint-plugin/src/util/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
isVariableDeclaration,
1212
unionTypeParts,
1313
isPropertyAssignment,
14+
isBinaryExpression,
1415
} from 'tsutils';
1516
import * as ts from 'typescript';
1617

@@ -498,6 +499,13 @@ export function getContextualType(
498499
return checker.getContextualType(parent);
499500
} else if (isPropertyAssignment(parent) && isIdentifier(node)) {
500501
return checker.getContextualType(node);
502+
} else if (
503+
isBinaryExpression(parent) &&
504+
parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
505+
parent.right === node
506+
) {
507+
// is RHS of assignment
508+
return checker.getTypeAtLocation(parent.left);
501509
} else if (
502510
![ts.SyntaxKind.TemplateSpan, ts.SyntaxKind.JsxExpression].includes(
503511
parent.kind,

packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,22 @@ const c = <const>[...a, ...b];
186186
{
187187
code: "const a = <const>{ foo: 'foo' };",
188188
},
189+
{
190+
code: `
191+
let a: number | undefined;
192+
let b: number | undefined;
193+
let c: number;
194+
a = b;
195+
c = b!;
196+
a! -= 1;
197+
`,
198+
},
199+
{
200+
code: `
201+
let a: { b?: string } | undefined;
202+
a!.b = '';
203+
`,
204+
},
189205
],
190206

191207
invalid: [
@@ -451,5 +467,29 @@ function Test(props: { id?: string | number }) {
451467
],
452468
filename: 'react.tsx',
453469
},
470+
{
471+
code: `
472+
let x: number | undefined;
473+
let y: number | undefined;
474+
y = x!;
475+
y! = 0;
476+
`,
477+
output: `
478+
let x: number | undefined;
479+
let y: number | undefined;
480+
y = x;
481+
y = 0;
482+
`,
483+
errors: [
484+
{
485+
messageId: 'contextuallyUnnecessary',
486+
line: 4,
487+
},
488+
{
489+
messageId: 'contextuallyUnnecessary',
490+
line: 5,
491+
},
492+
],
493+
},
454494
],
455495
});

0 commit comments

Comments
 (0)