Skip to content

Commit c4d5a56

Browse files
authored
fix(eslint-plugin): replace unclear "error typed" with more helpful description (#11704)
1 parent e29bdb0 commit c4d5a56

File tree

5 files changed

+150
-97
lines changed

5 files changed

+150
-97
lines changed

packages/eslint-plugin/src/rules/no-unsafe-call.ts

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import {
1212
} from '../util';
1313

1414
export type MessageIds =
15+
| 'errorCall'
16+
| 'errorCallThis'
17+
| 'errorNew'
18+
| 'errorTemplateTag'
1519
| 'unsafeCall'
1620
| 'unsafeCallThis'
1721
| 'unsafeNew'
@@ -27,13 +31,18 @@ export default createRule<[], MessageIds>({
2731
requiresTypeChecking: true,
2832
},
2933
messages: {
30-
unsafeCall: 'Unsafe call of a(n) {{type}} typed value.',
34+
errorCall: 'Unsafe call of a type that could not be resolved.',
35+
errorCallThis: 'Unsafe call of a `this` type that could not be resolved.',
36+
errorNew: 'Unsafe construction of a type that could not be resolved.',
37+
errorTemplateTag:
38+
'Unsafe use of a template tag whose type could not be resolved.',
39+
unsafeCall: 'Unsafe call of {{type}} typed value.',
3140
unsafeCallThis: [
32-
'Unsafe call of a(n) {{type}} typed value. `this` is typed as {{type}}.',
41+
'Unsafe call of {{type}} typed value. `this` is typed as {{type}}.',
3342
'You can try to fix this by turning on the `noImplicitThis` compiler option, or adding a `this` parameter to the function.',
3443
].join('\n'),
35-
unsafeNew: 'Unsafe construction of a(n) {{type}} typed value.',
36-
unsafeTemplateTag: 'Unsafe use of a(n) {{type}} typed template tag.',
44+
unsafeNew: 'Unsafe construction of {{type}} typed value.',
45+
unsafeTemplateTag: 'Unsafe use of {{type}} typed template tag.',
3746
},
3847
schema: [],
3948
},
@@ -49,7 +58,8 @@ export default createRule<[], MessageIds>({
4958
function checkCall(
5059
node: TSESTree.Node,
5160
reportingNode: TSESTree.Node,
52-
messageId: MessageIds,
61+
unsafeMessageId: Extract<MessageIds, `unsafe${string}`>,
62+
errorMessageId: Extract<MessageIds, `error${string}`>,
5363
): void {
5464
const type = getConstrainedTypeAtLocation(services, node);
5565

@@ -63,17 +73,18 @@ export default createRule<[], MessageIds>({
6373
getConstrainedTypeAtLocation(services, thisExpression),
6474
)
6575
) {
66-
messageId = 'unsafeCallThis';
76+
unsafeMessageId = 'unsafeCallThis';
77+
errorMessageId = 'errorCallThis';
6778
}
6879
}
6980

7081
const isErrorType = tsutils.isIntrinsicErrorType(type);
7182

7283
context.report({
7384
node: reportingNode,
74-
messageId,
85+
messageId: isErrorType ? errorMessageId : unsafeMessageId,
7586
data: {
76-
type: isErrorType ? '`error` type' : '`any`',
87+
type: 'an `any`',
7788
},
7889
});
7990
return;
@@ -98,7 +109,7 @@ export default createRule<[], MessageIds>({
98109
}
99110

100111
const callSignatures = type.getCallSignatures();
101-
if (messageId === 'unsafeNew') {
112+
if (unsafeMessageId === 'unsafeNew') {
102113
if (
103114
callSignatures.some(
104115
signature =>
@@ -113,9 +124,9 @@ export default createRule<[], MessageIds>({
113124

114125
context.report({
115126
node: reportingNode,
116-
messageId,
127+
messageId: unsafeMessageId,
117128
data: {
118-
type: '`Function`',
129+
type: 'a `Function`',
119130
},
120131
});
121132
return;
@@ -126,13 +137,13 @@ export default createRule<[], MessageIds>({
126137
'CallExpression > *.callee'(
127138
node: TSESTree.CallExpression['callee'],
128139
): void {
129-
checkCall(node, node, 'unsafeCall');
140+
checkCall(node, node, 'unsafeCall', 'errorCall');
130141
},
131142
NewExpression(node): void {
132-
checkCall(node.callee, node, 'unsafeNew');
143+
checkCall(node.callee, node, 'unsafeNew', 'errorNew');
133144
},
134145
'TaggedTemplateExpression > *.tag'(node: TSESTree.Node): void {
135-
checkCall(node, node, 'unsafeTemplateTag');
146+
checkCall(node, node, 'unsafeTemplateTag', 'errorTemplateTag');
136147
},
137148
};
138149
},

packages/eslint-plugin/src/rules/no-unsafe-member-access.ts

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { TSESTree } from '@typescript-eslint/utils';
2-
import type * as ts from 'typescript';
32

43
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
54
import * as tsutils from 'ts-api-utils';
@@ -18,18 +17,16 @@ const enum State {
1817
Chained = 3,
1918
}
2019

21-
function createDataType(type: ts.Type): '`any`' | '`error` typed' {
22-
const isErrorType = tsutils.isIntrinsicErrorType(type);
23-
return isErrorType ? '`error` typed' : '`any`';
24-
}
25-
2620
export type Options = [
2721
{
2822
allowOptionalChaining?: boolean;
2923
},
3024
];
3125

3226
export type MessageIds =
27+
| 'errorComputedMemberAccess'
28+
| 'errorMemberExpression'
29+
| 'errorThisMemberExpression'
3330
| 'unsafeComputedMemberAccess'
3431
| 'unsafeMemberExpression'
3532
| 'unsafeThisMemberExpression';
@@ -44,10 +41,18 @@ export default createRule<Options, MessageIds>({
4441
requiresTypeChecking: true,
4542
},
4643
messages: {
44+
errorComputedMemberAccess:
45+
'The type of computed name {{property}} cannot be resolved.',
46+
errorMemberExpression:
47+
'Unsafe member access {{property}} on a type that cannot be resolved.',
48+
errorThisMemberExpression: [
49+
'Unsafe member access {{property}}. The type of `this` cannot be resolved.',
50+
'You can try to fix this by turning on the `noImplicitThis` compiler option, or adding a `this` parameter to the function.',
51+
].join('\n'),
4752
unsafeComputedMemberAccess:
48-
'Computed name {{property}} resolves to an {{type}} value.',
53+
'Computed name {{property}} resolves to an `any` value.',
4954
unsafeMemberExpression:
50-
'Unsafe member access {{property}} on an {{type}} value.',
55+
'Unsafe member access {{property}} on an `any` value.',
5156
unsafeThisMemberExpression: [
5257
'Unsafe member access {{property}} on an `any` value. `this` is typed as `any`.',
5358
'You can try to fix this by turning on the `noImplicitThis` compiler option, or adding a `this` parameter to the function.',
@@ -118,27 +123,34 @@ export default createRule<Options, MessageIds>({
118123
if (state === State.Unsafe) {
119124
const propertyName = context.sourceCode.getText(node.property);
120125

121-
let messageId: MessageIds = 'unsafeMemberExpression';
126+
let messageId: MessageIds | undefined;
122127

123128
if (!isNoImplicitThis) {
124129
// `this.foo` or `this.foo[bar]`
125130
const thisExpression = getThisExpression(node);
126-
127-
if (
128-
thisExpression &&
129-
isTypeAnyType(
130-
getConstrainedTypeAtLocation(services, thisExpression),
131-
)
132-
) {
133-
messageId = 'unsafeThisMemberExpression';
131+
if (thisExpression) {
132+
const thisType = getConstrainedTypeAtLocation(
133+
services,
134+
thisExpression,
135+
);
136+
if (isTypeAnyType(thisType)) {
137+
messageId = tsutils.isIntrinsicErrorType(thisType)
138+
? 'errorThisMemberExpression'
139+
: 'unsafeThisMemberExpression';
140+
}
134141
}
135142
}
136143

144+
if (!messageId) {
145+
messageId = tsutils.isIntrinsicErrorType(type)
146+
? 'errorMemberExpression'
147+
: 'unsafeMemberExpression';
148+
}
149+
137150
context.report({
138151
node: node.property,
139152
messageId,
140153
data: {
141-
type: createDataType(type),
142154
property: node.computed ? `[${propertyName}]` : `.${propertyName}`,
143155
},
144156
});
@@ -179,9 +191,10 @@ export default createRule<Options, MessageIds>({
179191
const propertyName = context.sourceCode.getText(node);
180192
context.report({
181193
node,
182-
messageId: 'unsafeComputedMemberAccess',
194+
messageId: tsutils.isIntrinsicErrorType(type)
195+
? 'errorComputedMemberAccess'
196+
: 'unsafeComputedMemberAccess',
183197
data: {
184-
type: createDataType(type),
185198
property: `[${propertyName}]`,
186199
},
187200
});

packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unsafe-call.shot

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)