Skip to content

Commit 0471e12

Browse files
committed
feat(eslint-plugin): [no-unsafe-enum-comparison] add switch suggestion
Closes typescript-eslint#7643
1 parent 4e23591 commit 0471e12

File tree

2 files changed

+77
-9
lines changed

2 files changed

+77
-9
lines changed

Diff for: packages/eslint-plugin/src/rules/no-unsafe-enum-comparison.ts

+61-5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,27 @@ function typeViolates(leftTypeParts: ts.Type[], right: ts.Type): boolean {
2525
);
2626
}
2727

28+
function getEnumKeyForLiteral(
29+
leftEnumTypes: ts.Type[],
30+
rightNode: TSESTree.Node,
31+
): string | null {
32+
const right = util.getStaticValue(rightNode);
33+
34+
if (right === null) {
35+
return null;
36+
}
37+
38+
for (const leftEnumType of leftEnumTypes) {
39+
if (leftEnumType.value === right.value) {
40+
const enumParentName = leftEnumType.symbol.parent.name;
41+
42+
return `${enumParentName}.${leftEnumType.symbol.name}`;
43+
}
44+
}
45+
46+
return null;
47+
}
48+
2849
/**
2950
* @returns What type a type's enum value is (number or string), if either.
3051
*/
@@ -48,6 +69,8 @@ export default util.createRule({
4869
messages: {
4970
mismatched:
5071
'The two values in this comparison do not have a shared enum type.',
72+
mismatchedSimilar:
73+
'The two values in this comparison do not have a shared enum type. Did you mean to compare to `{{replacement}}`?',
5174
},
5275
schema: [],
5376
},
@@ -100,11 +123,44 @@ export default util.createRule({
100123
}
101124
}
102125

103-
if (
104-
typeViolates(leftTypeParts, right) ||
105-
typeViolates(rightTypeParts, left)
106-
) {
107-
context.report({
126+
if (typeViolates(leftTypeParts, right)) {
127+
const leftEnumKey = getEnumKeyForLiteral(leftEnumTypes, node.right);
128+
129+
if (leftEnumKey) {
130+
// TODO: Add fixer.
131+
return context.report({
132+
messageId: 'mismatchedSimilar',
133+
node,
134+
data: {
135+
replacement: leftEnumKey,
136+
},
137+
});
138+
}
139+
140+
return context.report({
141+
messageId: 'mismatched',
142+
node,
143+
});
144+
}
145+
146+
if (typeViolates(rightTypeParts, left)) {
147+
const rightEnumKey = getEnumKeyForLiteral(
148+
[...rightEnumTypes.values()],
149+
node.left,
150+
);
151+
152+
if (rightEnumKey) {
153+
// TODO: Add fixer.
154+
return context.report({
155+
messageId: 'mismatchedSimilar',
156+
node,
157+
data: {
158+
replacement: rightEnumKey,
159+
},
160+
});
161+
}
162+
163+
return context.report({
108164
messageId: 'mismatched',
109165
node,
110166
});

Diff for: packages/eslint-plugin/tests/rules/no-unsafe-enum-comparison.test.ts

+16-4
Original file line numberDiff line numberDiff line change
@@ -545,10 +545,22 @@ ruleTester.run('strict-enums-comparison', rule, {
545545
mixed === 1;
546546
`,
547547
errors: [
548-
{ messageId: 'mismatched' },
549-
{ messageId: 'mismatched' },
550-
{ messageId: 'mismatched' },
551-
{ messageId: 'mismatched' },
548+
{
549+
message:
550+
'The two values in this comparison do not have a shared enum type. Did you mean to compare to `Str.A`?',
551+
},
552+
{
553+
message:
554+
'The two values in this comparison do not have a shared enum type. Did you mean to compare to `Num.B`?',
555+
},
556+
{
557+
message:
558+
'The two values in this comparison do not have a shared enum type. Did you mean to compare to `Mixed.A`?',
559+
},
560+
{
561+
message:
562+
'The two values in this comparison do not have a shared enum type. Did you mean to compare to `Mixed.B`?',
563+
},
552564
],
553565
},
554566
{

0 commit comments

Comments
 (0)