From 1a6e28d348c6aaca9a0c5f108bd4cfa1575e479b Mon Sep 17 00:00:00 2001 From: Hasegawa-Yukihiro Date: Thu, 6 Jun 2024 20:40:41 +0900 Subject: [PATCH 1/4] fix: support error type --- .../src/rules/no-unsafe-member-access.ts | 4 +++- .../rules/no-unsafe-member-access.test.ts | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts index f98e59b4cd65..611197947d66 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts @@ -26,7 +26,7 @@ export default createRule({ }, messages: { unsafeMemberExpression: - 'Unsafe member access {{property}} on an `any` value.', + 'Unsafe member access {{property}} on an {{type}} value.', unsafeThisMemberExpression: [ 'Unsafe member access {{property}} on an `any` value. `this` is typed as `any`.', 'You can try to fix this by turning on the `noImplicitThis` compiler option, or adding a `this` parameter to the function.', @@ -86,12 +86,14 @@ export default createRule({ messageId = 'unsafeThisMemberExpression'; } } + const isErrorType = tsutils.isIntrinsicErrorType(type); context.report({ node: node.property, messageId, data: { property: node.computed ? `[${propertyName}]` : `.${propertyName}`, + type: isErrorType ? '`error`' : '`any`', }, }); } diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts index 292c52759c0d..9d46f0e24f27 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts @@ -75,6 +75,7 @@ function foo(x: any) { column: 5, endColumn: 6, data: { + type: '`any`', property: '.a', }, }, @@ -93,6 +94,7 @@ function foo(x: any) { column: 5, endColumn: 6, data: { + type: '`any`', property: '.a', }, }, @@ -111,6 +113,7 @@ function foo(x: { a: any }) { column: 7, endColumn: 8, data: { + type: '`any`', property: '.b', }, }, @@ -129,6 +132,7 @@ function foo(x: any) { column: 5, endColumn: 8, data: { + type: '`any`', property: "['a']", }, }, @@ -147,6 +151,7 @@ function foo(x: any) { column: 5, endColumn: 8, data: { + type: '`any`', property: "['a']", }, }, @@ -154,6 +159,25 @@ function foo(x: any) { }, { code: ` +let value: NotKnown; + +value.property; + `, + errors: [ + { + messageId: 'unsafeMemberExpression', + line: 4, + column: 7, + endColumn: 15, + data: { + type: '`error`', + property: '.property', + }, + }, + ], + }, + { + code: ` function foo(x: { a: number }, y: any) { x[y]; } From 866d68d0e452119f3ecf65a63472a2090fc9218c Mon Sep 17 00:00:00 2001 From: Hasegawa-Yukihiro Date: Sun, 9 Jun 2024 00:48:00 +0900 Subject: [PATCH 2/4] fix: add "typed" --- packages/eslint-plugin/src/rules/no-unsafe-member-access.ts | 2 +- .../eslint-plugin/tests/rules/no-unsafe-member-access.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts index 611197947d66..305276613502 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts @@ -93,7 +93,7 @@ export default createRule({ messageId, data: { property: node.computed ? `[${propertyName}]` : `.${propertyName}`, - type: isErrorType ? '`error`' : '`any`', + type: isErrorType ? '`error` typed' : '`any`', }, }); } diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts index 9d46f0e24f27..6475d5c9df9b 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts @@ -170,7 +170,7 @@ value.property; column: 7, endColumn: 15, data: { - type: '`error`', + type: '`error` typed', property: '.property', }, }, From f36ef89b16e18cf809ae6e995593e24329c92077 Mon Sep 17 00:00:00 2001 From: Hasegawa-Yukihiro Date: Sun, 9 Jun 2024 10:14:23 +0900 Subject: [PATCH 3/4] fix: Fixed the case of unsafeComputedMemberAccess as well. --- .../src/rules/no-unsafe-member-access.ts | 12 ++++++--- .../rules/no-unsafe-member-access.test.ts | 25 +++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts index 305276613502..260650d198c7 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts @@ -1,6 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; +import type * as ts from 'typescript'; import { createRule, @@ -15,6 +16,11 @@ const enum State { Safe = 2, } +function createDataType(type: ts.Type): '`error` typed' | '`any`' { + const isErrorType = tsutils.isIntrinsicErrorType(type); + return isErrorType ? '`error` typed' : '`any`'; +} + export default createRule({ name: 'no-unsafe-member-access', meta: { @@ -32,7 +38,7 @@ export default createRule({ 'You can try to fix this by turning on the `noImplicitThis` compiler option, or adding a `this` parameter to the function.', ].join('\n'), unsafeComputedMemberAccess: - 'Computed name {{property}} resolves to an any value.', + 'Computed name {{property}} resolves to an {{type}} value.', }, schema: [], }, @@ -86,14 +92,13 @@ export default createRule({ messageId = 'unsafeThisMemberExpression'; } } - const isErrorType = tsutils.isIntrinsicErrorType(type); context.report({ node: node.property, messageId, data: { property: node.computed ? `[${propertyName}]` : `.${propertyName}`, - type: isErrorType ? '`error` typed' : '`any`', + type: createDataType(type), }, }); } @@ -129,6 +134,7 @@ export default createRule({ messageId: 'unsafeComputedMemberAccess', data: { property: `[${propertyName}]`, + type: createDataType(type), }, }); } diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts index 6475d5c9df9b..a35d14c1e0c8 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts @@ -190,6 +190,7 @@ function foo(x: { a: number }, y: any) { endColumn: 6, data: { property: '[y]', + type: '`any`', }, }, ], @@ -208,6 +209,7 @@ function foo(x?: { a: number }, y: any) { endColumn: 8, data: { property: '[y]', + type: '`any`', }, }, ], @@ -226,6 +228,7 @@ function foo(x: { a: number }, y: any) { endColumn: 12, data: { property: '[y += 1]', + type: '`any`', }, }, ], @@ -244,6 +247,7 @@ function foo(x: { a: number }, y: any) { endColumn: 13, data: { property: '[1 as any]', + type: '`any`', }, }, ], @@ -262,6 +266,7 @@ function foo(x: { a: number }, y: any) { endColumn: 8, data: { property: '[y()]', + type: '`any`', }, }, ], @@ -280,6 +285,26 @@ function foo(x: string[], y: any) { endColumn: 6, data: { property: '[y]', + type: '`any`', + }, + }, + ], + }, + { + code: ` +function foo(x: { a: number }, y: NotKnown) { + x[y]; +} + `, + errors: [ + { + messageId: 'unsafeComputedMemberAccess', + line: 3, + column: 5, + endColumn: 6, + data: { + property: '[y]', + type: '`error` typed', }, }, ], From 0498869afd5480f26d9e06d6d63b3ab8f26c5edf Mon Sep 17 00:00:00 2001 From: Hasegawa-Yukihiro Date: Sun, 9 Jun 2024 11:26:15 +0900 Subject: [PATCH 4/4] test: update snapshot --- .../docs-eslint-output-snapshots/no-unsafe-member-access.shot | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unsafe-member-access.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unsafe-member-access.shot index 33b46a7e5921..ac2342c31da5 100644 --- a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unsafe-member-access.shot +++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unsafe-member-access.shot @@ -27,9 +27,9 @@ nestedAny.prop[key]; // Using an any to access a member is unsafe const arr = [1, 2, 3]; arr[anyVar]; - ~~~~~~ Computed name [anyVar] resolves to an any value. + ~~~~~~ Computed name [anyVar] resolves to an \`any\` value. nestedAny[anyVar]; - ~~~~~~ Computed name [anyVar] resolves to an any value. + ~~~~~~ Computed name [anyVar] resolves to an \`any\` value. " `;