From 752940039df920ee0fd9473d6e5094fa2d5b1dd0 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Thu, 5 Dec 2024 12:57:59 -0500 Subject: [PATCH 01/13] Add failing test case for unsafe type assertion with constrained generic types --- .../rules/no-unsafe-type-assertion.test.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts index aa73bc2dae4d..5ad331081a7b 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts @@ -1041,3 +1041,37 @@ a as Bar; ], }); }); + +describe('generic assertions', () => { + ruleTester.run('no-unsafe-type-assertion', rule, { + valid: [ + ` +type Obj = { foo: string }; +function func(a: T): T { + const b = { ...a } as T; + return b; +} + `, + ], + invalid: [ + { + code: ` +type Obj = { foo: string }; +function func() { + const b = { foo: 'hi' } as T; + return b; +} + `, + errors: [ + { + column: 13, + endColumn: 31, + endLine: 4, + line: 4, + messageId: 'unsafeTypeAssertion', + }, + ], + }, + ], + }); +}); From 9117da02135c25bdc528ab5cc60a1d3845b6a9f7 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Thu, 5 Dec 2024 12:58:59 -0500 Subject: [PATCH 02/13] =?UTF-8?q?Use=20actual=20type=20instead=20of=20?= =?UTF-8?q?=E2=80=9Cconstrained=20type=E2=80=9D=20for=20no-unsafe-type-ass?= =?UTF-8?q?ertion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/rules/no-unsafe-type-assertion.ts | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts index 06c3dd44615a..ca60c66aa4f4 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts @@ -5,7 +5,6 @@ import * as ts from 'typescript'; import { createRule, - getConstrainedTypeAtLocation, getParserServices, isTypeAnyType, isTypeUnknownType, @@ -49,14 +48,8 @@ export default createRule({ function checkExpression( node: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion, ): void { - const expressionType = getConstrainedTypeAtLocation( - services, - node.expression, - ); - const assertedType = getConstrainedTypeAtLocation( - services, - node.typeAnnotation, - ); + const expressionType = services.getTypeAtLocation(node.expression); + const assertedType = services.getTypeAtLocation(node.typeAnnotation); if (expressionType === assertedType) { return; @@ -115,12 +108,12 @@ export default createRule({ // Use the widened type in case of an object literal so `isTypeAssignableTo()` // won't fail on excess property check. - const nodeWidenedType = isObjectLiteralType(expressionType) + const expressionWidenedType = isObjectLiteralType(expressionType) ? checker.getWidenedType(expressionType) : expressionType; const isAssertionSafe = checker.isTypeAssignableTo( - nodeWidenedType, + expressionWidenedType, assertedType, ); From ece33d8eab190983fb7c53a7fd470287406c07e0 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Thu, 5 Dec 2024 13:18:32 -0500 Subject: [PATCH 03/13] tweak test cases --- .../rules/no-unsafe-type-assertion.test.ts | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts index 5ad331081a7b..c45594b98720 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts @@ -1047,9 +1047,8 @@ describe('generic assertions', () => { valid: [ ` type Obj = { foo: string }; -function func(a: T): T { - const b = { ...a } as T; - return b; +function func(a: T) { + const b = a as T; } `, ], @@ -1058,20 +1057,37 @@ function func(a: T): T { code: ` type Obj = { foo: string }; function func() { - const b = { foo: 'hi' } as T; - return b; + const myObj = { foo: 'hi' } as T; } `, errors: [ { - column: 13, - endColumn: 31, + column: 17, + endColumn: 35, endLine: 4, line: 4, messageId: 'unsafeTypeAssertion', }, ], }, + { + code: ` +type Obj = { foo: string }; +function func() { + const o: Obj = { foo: 'hi' }; + const myObj = o as T; +} + `, + errors: [ + { + column: 17, + endColumn: 23, + endLine: 5, + line: 5, + messageId: 'unsafeTypeAssertion', + }, + ], + }, ], }); }); From 354dc326b13bb09278050d36484b56446117b6c0 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Thu, 5 Dec 2024 14:22:51 -0500 Subject: [PATCH 04/13] =?UTF-8?q?Custom=20error=20message=20for=20?= =?UTF-8?q?=E2=80=9Cassignable=20to=20the=20constraint=E2=80=9D=20case?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/rules/no-unsafe-type-assertion.ts | 38 +++++++++++++++---- .../rules/no-unsafe-type-assertion.test.ts | 24 +++++++++++- 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts index ca60c66aa4f4..c291556370f3 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts @@ -24,6 +24,8 @@ export default createRule({ 'Unsafe cast from {{type}} detected: consider using type guards or a safer cast.', unsafeToAnyTypeAssertion: 'Unsafe cast to {{type}} detected: consider using a more specific type to ensure safety.', + unsafeToConstrainedTypeAssertion: + "Unsafe type assertion: the original type is assignable to the constraint of type '{{type}}', but {{type}} could be instantiated with a different subtype of the constraint.", unsafeTypeAssertion: "Unsafe type assertion: type '{{type}}' is more narrow than the original type.", }, @@ -117,14 +119,36 @@ export default createRule({ assertedType, ); + // Check if the asserted type is a constrainted generic type to whose + // constraint the expression is assignable, in order to produce a more + // specific error message + const assertedTypeConstraint = + checker.getBaseConstraintOfType(assertedType); + const isAssignableToConstraint = + !!assertedTypeConstraint && + checker.isTypeAssignableTo( + expressionWidenedType, + assertedTypeConstraint, + ); + if (!isAssertionSafe) { - context.report({ - node, - messageId: 'unsafeTypeAssertion', - data: { - type: checker.typeToString(assertedType), - }, - }); + if (isAssignableToConstraint) { + context.report({ + node, + messageId: 'unsafeToConstrainedTypeAssertion', + data: { + type: checker.typeToString(assertedType), + }, + }); + } else { + context.report({ + node, + messageId: 'unsafeTypeAssertion', + data: { + type: checker.typeToString(assertedType), + }, + }); + } } } diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts index c45594b98720..0ae8164d4464 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts @@ -1066,7 +1066,7 @@ function func() { endColumn: 35, endLine: 4, line: 4, - messageId: 'unsafeTypeAssertion', + messageId: 'unsafeToConstrainedTypeAssertion', }, ], }, @@ -1084,6 +1084,28 @@ function func() { endColumn: 23, endLine: 5, line: 5, + messageId: 'unsafeToConstrainedTypeAssertion', + }, + ], + }, + // https://github.com/typescript-eslint/typescript-eslint/issues/10453#issuecomment-2520964068 + // the custom error message should only occur if the expression type is + // *actually* assignable to the constraint of the asserted type + { + code: ` +export function myfunc( + input: number, +): CustomObjectT { + const newCustomObject = input as CustomObjectT; + return newCustomObject; +} + `, + errors: [ + { + column: 27, + endColumn: 49, + endLine: 5, + line: 5, messageId: 'unsafeTypeAssertion', }, ], From 05bdf78b1038aeca31abe38155a2b77c69537e7a Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Thu, 5 Dec 2024 14:35:31 -0500 Subject: [PATCH 05/13] =?UTF-8?q?rename=20=E2=80=9Cassignable=20to=20the?= =?UTF-8?q?=20constraint=E2=80=9D=20error=20message?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eslint-plugin/src/rules/no-unsafe-type-assertion.ts | 6 +++--- .../tests/rules/no-unsafe-type-assertion.test.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts index c291556370f3..11d26058152e 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts @@ -24,10 +24,10 @@ export default createRule({ 'Unsafe cast from {{type}} detected: consider using type guards or a safer cast.', unsafeToAnyTypeAssertion: 'Unsafe cast to {{type}} detected: consider using a more specific type to ensure safety.', - unsafeToConstrainedTypeAssertion: - "Unsafe type assertion: the original type is assignable to the constraint of type '{{type}}', but {{type}} could be instantiated with a different subtype of the constraint.", unsafeTypeAssertion: "Unsafe type assertion: type '{{type}}' is more narrow than the original type.", + unsafeTypeAssertionAssignableToConstraint: + "Unsafe type assertion: the original type is assignable to the constraint of type '{{type}}', but {{type}} could be instantiated with a different subtype of the constraint.", }, schema: [], }, @@ -135,7 +135,7 @@ export default createRule({ if (isAssignableToConstraint) { context.report({ node, - messageId: 'unsafeToConstrainedTypeAssertion', + messageId: 'unsafeTypeAssertionAssignableToConstraint', data: { type: checker.typeToString(assertedType), }, diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts index 0ae8164d4464..950ad67524c1 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts @@ -1066,7 +1066,7 @@ function func() { endColumn: 35, endLine: 4, line: 4, - messageId: 'unsafeToConstrainedTypeAssertion', + messageId: 'unsafeTypeAssertionAssignableToConstraint', }, ], }, @@ -1084,7 +1084,7 @@ function func() { endColumn: 23, endLine: 5, line: 5, - messageId: 'unsafeToConstrainedTypeAssertion', + messageId: 'unsafeTypeAssertionAssignableToConstraint', }, ], }, From 357853296e2f78980a96a457698285906a41acd9 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Thu, 5 Dec 2024 14:37:09 -0500 Subject: [PATCH 06/13] spelling --- packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts index 11d26058152e..79c3c51e3034 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts @@ -119,7 +119,7 @@ export default createRule({ assertedType, ); - // Check if the asserted type is a constrainted generic type to whose + // Check if the asserted type is a constrained generic type to whose // constraint the expression is assignable, in order to produce a more // specific error message const assertedTypeConstraint = From a1cf41769685df8ff8201ffaed935c8a7baab78a Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Thu, 5 Dec 2024 14:55:38 -0500 Subject: [PATCH 07/13] tweak message --- packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts index 79c3c51e3034..d80d00d9948b 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts @@ -27,7 +27,7 @@ export default createRule({ unsafeTypeAssertion: "Unsafe type assertion: type '{{type}}' is more narrow than the original type.", unsafeTypeAssertionAssignableToConstraint: - "Unsafe type assertion: the original type is assignable to the constraint of type '{{type}}', but {{type}} could be instantiated with a different subtype of the constraint.", + "Unsafe type assertion: the original type is assignable to the constraint of type '{{type}}', but '{{type}}' could be instantiated with a different subtype of its constraint.", }, schema: [], }, From d7a760043d65f409841bbb22871d09533ed6ce5e Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Fri, 6 Dec 2024 15:58:11 -0500 Subject: [PATCH 08/13] Add new test cases from @kirkwaiblinger --- .../rules/no-unsafe-type-assertion.test.ts | 236 ++++++++++++++++++ 1 file changed, 236 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts index 950ad67524c1..8488a740cb39 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts @@ -1049,6 +1049,21 @@ describe('generic assertions', () => { type Obj = { foo: string }; function func(a: T) { const b = a as T; +} + `, + ` +function parameterExtendsOtherParameter(x: T, y: V) { + y as T; +} + `, + ` +function unconstrainedToUnknown(x: T) { + x as unknown; +} + `, + ` +function stringToWider(x: T) { + x as number | string; // allowed } `, ], @@ -1110,6 +1125,227 @@ export function myfunc( }, ], }, + // https://github.com/typescript-eslint/typescript-eslint/pull/10461#discussion_r1873887553 + // 1. non-parameter -> parameter assertions + { + code: ` +function unknownConstraint(x: T, y: string) { + y as T; // banned; generic arbitrary subtype +} + `, + errors: [ + { + column: 3, + endColumn: 9, + endLine: 3, + line: 3, + messageId: 'unsafeTypeAssertionAssignableToConstraint', + }, + ], + }, + { + code: ` +function unconstrained(x: T, y: string) { + y as T; +} + `, + errors: [ + { + column: 3, + endColumn: 9, + endLine: 3, + line: 3, + messageId: 'unsafeToUnconstrainedTypeAssertion', + }, + ], + }, + { + code: ` +// constraint of any functions like constraint of \`unknown\` +// (even the TS error message has this verbiage) +function anyConstraint(x: T, y: string) { + y as T; // banned; generic arbitrary subtype +} + `, + errors: [ + { + column: 3, + endColumn: 9, + endLine: 5, + line: 5, + messageId: 'unsafeTypeAssertionAssignableToConstraint', + }, + ], + }, + { + code: ` +function constraintWiderThanUncastType( + x: T, + y: string, +) { + y as T; // banned; assignable to constraint +} + `, + errors: [ + { + column: 3, + endColumn: 9, + endLine: 6, + line: 6, + messageId: 'unsafeTypeAssertionAssignableToConstraint', + }, + ], + }, + { + code: ` +function constraintEqualUncastType(x: T, y: string) { + y as T; // banned; assignable to constraint +} + `, + errors: [ + { + column: 3, + endColumn: 9, + endLine: 3, + line: 3, + messageId: 'unsafeTypeAssertionAssignableToConstraint', + }, + ], + }, + { + code: ` +function constraintNarrowerThanUncastType( + x: T, + y: string | number, +) { + y as T; // banned; *not* assignable to constraint +} + `, + errors: [ + { + column: 3, + endColumn: 9, + endLine: 6, + line: 6, + messageId: 'unsafeTypeAssertion', + }, + ], + }, + { + code: ` +function assertFromAny(x: T, y: any) { + y as T; // banned; just an \`any\` complaint. Not a generic subtype. +} + `, + errors: [ + { + column: 3, + endColumn: 9, + endLine: 3, + line: 3, + messageId: 'unsafeOfAnyTypeAssertion', + }, + ], + }, + // 2. parameter -> parameter assertions + { + code: ` +function parameterExtendsOtherParameter(x: T, y: V) { + y as T; // allowed (as above) + x as V; // banned; unconstrained arbitrary type +} + `, + errors: [ + { + column: 3, + endColumn: 9, + endLine: 4, + line: 4, + messageId: 'unsafeTypeAssertionAssignableToConstraint', + }, + ], + }, + { + code: ` +function twoUnconstrained(x: T, y: V) { + y as T; +} + `, + errors: [ + { + column: 3, + endColumn: 9, + endLine: 3, + line: 3, + messageId: 'unsafeToUnconstrainedTypeAssertion', + }, + ], + }, + // 2. parameter -> non-parameter assertions + { + code: ` +function toNarrower(x: T, y: string) { + x as string; // banned; ordinary 'string' narrower than 'T'. +} + `, + errors: [ + { + column: 3, + endColumn: 14, + endLine: 3, + line: 3, + messageId: 'unsafeTypeAssertion', + }, + ], + }, + { + code: ` +function unconstrainedToAny(x: T) { + x as any; +} + `, + errors: [ + { + column: 3, + endColumn: 11, + endLine: 3, + line: 3, + messageId: 'unsafeToAnyTypeAssertion', + }, + ], + }, + { + code: ` +function stringToAny(x: T) { + x as any; +} + `, + errors: [ + { + column: 3, + endColumn: 11, + endLine: 3, + line: 3, + messageId: 'unsafeToAnyTypeAssertion', + }, + ], + }, + { + code: ` +function stringToNarrower(x: T) { + x as 'a' | 'b'; +} + `, + errors: [ + { + column: 3, + endColumn: 17, + endLine: 3, + line: 3, + messageId: 'unsafeTypeAssertion', + }, + ], + }, ], }); }); From 60cba854b206718b72a962fd3e30b337027c8597 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Fri, 6 Dec 2024 16:01:49 -0500 Subject: [PATCH 09/13] Move isAssignableToConstraint check into isAssertionSafe --- .../src/rules/no-unsafe-type-assertion.ts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts index d80d00d9948b..991ff74cdf92 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts @@ -119,19 +119,19 @@ export default createRule({ assertedType, ); - // Check if the asserted type is a constrained generic type to whose - // constraint the expression is assignable, in order to produce a more - // specific error message - const assertedTypeConstraint = - checker.getBaseConstraintOfType(assertedType); - const isAssignableToConstraint = - !!assertedTypeConstraint && - checker.isTypeAssignableTo( - expressionWidenedType, - assertedTypeConstraint, - ); - if (!isAssertionSafe) { + // Check if the asserted type is a constrained generic type to whose + // constraint the expression is assignable, in order to produce a more + // specific error message + const assertedTypeConstraint = + checker.getBaseConstraintOfType(assertedType); + const isAssignableToConstraint = + !!assertedTypeConstraint && + checker.isTypeAssignableTo( + expressionWidenedType, + assertedTypeConstraint, + ); + if (isAssignableToConstraint) { context.report({ node, From e560ef3a8d2fecc99eeca25b59760e64c3b42db5 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Fri, 6 Dec 2024 16:35:23 -0500 Subject: [PATCH 10/13] Properly handle unconstrained type parameters, including new error message + light refactor to prefer early returns over nested conditionals --- .../src/rules/no-unsafe-type-assertion.ts | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts index 991ff74cdf92..f76039d077ab 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts @@ -24,6 +24,8 @@ export default createRule({ 'Unsafe cast from {{type}} detected: consider using type guards or a safer cast.', unsafeToAnyTypeAssertion: 'Unsafe cast to {{type}} detected: consider using a more specific type to ensure safety.', + unsafeToUnconstrainedTypeAssertion: + "Unsafe type assertion: '{{type}}' could be instantiated with an arbitrary type which could be unrelated to the original type.", unsafeTypeAssertion: "Unsafe type assertion: type '{{type}}' is more narrow than the original type.", unsafeTypeAssertionAssignableToConstraint: @@ -118,38 +120,52 @@ export default createRule({ expressionWidenedType, assertedType, ); + if (isAssertionSafe) { + return; + } - if (!isAssertionSafe) { - // Check if the asserted type is a constrained generic type to whose - // constraint the expression is assignable, in order to produce a more - // specific error message + // Produce a more specific error message when targeting a type parameter + if (tsutils.isTypeParameter(assertedType)) { const assertedTypeConstraint = checker.getBaseConstraintOfType(assertedType); - const isAssignableToConstraint = - !!assertedTypeConstraint && - checker.isTypeAssignableTo( - expressionWidenedType, - assertedTypeConstraint, - ); - - if (isAssignableToConstraint) { + if (!assertedTypeConstraint) { + // asserting to an unconstrained type parameter is unsafe context.report({ node, - messageId: 'unsafeTypeAssertionAssignableToConstraint', + messageId: 'unsafeToUnconstrainedTypeAssertion', data: { type: checker.typeToString(assertedType), }, }); - } else { + return; + } + + // special case message if the original type is assignable to the + // constraint of the target type parameter + const isAssignableToConstraint = checker.isTypeAssignableTo( + expressionWidenedType, + assertedTypeConstraint, + ); + if (isAssignableToConstraint) { context.report({ node, - messageId: 'unsafeTypeAssertion', + messageId: 'unsafeTypeAssertionAssignableToConstraint', data: { type: checker.typeToString(assertedType), }, }); + return; } } + + // General error message + context.report({ + node, + messageId: 'unsafeTypeAssertion', + data: { + type: checker.typeToString(assertedType), + }, + }); } return { From c39c4b72645a86028b46a6837c7c06744eafb54e Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Fri, 6 Dec 2024 16:41:17 -0500 Subject: [PATCH 11/13] =?UTF-8?q?distinguish=20between=20=E2=80=9Cparamete?= =?UTF-8?q?r=20extends=20other=20parameter=E2=80=9D=20and=20=E2=80=9Cparam?= =?UTF-8?q?eter=20extends=20unconstrained=20parameter=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rules/no-unsafe-type-assertion.test.ts | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts index 8488a740cb39..5eb0ff223a22 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts @@ -1052,7 +1052,15 @@ function func(a: T) { } `, ` -function parameterExtendsOtherParameter(x: T, y: V) { +function parameterExtendsOtherParameter( + x: T, + y: V, +) { + y as T; +} + `, + ` +function parameterExtendsUnconstrainedParameter(x: T, y: V) { y as T; } `, @@ -1250,7 +1258,27 @@ function assertFromAny(x: T, y: any) { // 2. parameter -> parameter assertions { code: ` -function parameterExtendsOtherParameter(x: T, y: V) { +function parameterExtendsOtherParameter( + x: T, + y: V, +) { + y as T; // allowed + x as V; // banned; assignable to constraint +} + `, + errors: [ + { + column: 3, + endColumn: 9, + endLine: 7, + line: 7, + messageId: 'unsafeTypeAssertionAssignableToConstraint', + }, + ], + }, + { + code: ` +function parameterExtendsUnconstrainedParameter(x: T, y: V) { y as T; // allowed (as above) x as V; // banned; unconstrained arbitrary type } @@ -1261,7 +1289,7 @@ function parameterExtendsOtherParameter(x: T, y: V) { endColumn: 9, endLine: 4, line: 4, - messageId: 'unsafeTypeAssertionAssignableToConstraint', + messageId: 'unsafeToUnconstrainedTypeAssertion', }, ], }, From 504df896ea890caa567e7994f3eeba076d728f07 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Tue, 17 Dec 2024 11:36:38 -0500 Subject: [PATCH 12/13] clean up extra pieces in unit tests unit tests should only test one thing --- .../eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts index 5eb0ff223a22..af80fa51d156 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts @@ -1262,7 +1262,6 @@ function parameterExtendsOtherParameter( x: T, y: V, ) { - y as T; // allowed x as V; // banned; assignable to constraint } `, @@ -1279,7 +1278,6 @@ function parameterExtendsOtherParameter( { code: ` function parameterExtendsUnconstrainedParameter(x: T, y: V) { - y as T; // allowed (as above) x as V; // banned; unconstrained arbitrary type } `, From 239f3df6ce97297ea87df4f9e6dcdcd593f718d2 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Tue, 17 Dec 2024 11:05:11 -0700 Subject: [PATCH 13/13] test lines --- .../tests/rules/no-unsafe-type-assertion.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts index af80fa51d156..0c40f2996676 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-type-assertion.test.ts @@ -1269,8 +1269,8 @@ function parameterExtendsOtherParameter( { column: 3, endColumn: 9, - endLine: 7, - line: 7, + endLine: 6, + line: 6, messageId: 'unsafeTypeAssertionAssignableToConstraint', }, ], @@ -1285,8 +1285,8 @@ function parameterExtendsUnconstrainedParameter(x: T, y: V) { { column: 3, endColumn: 9, - endLine: 4, - line: 4, + endLine: 3, + line: 3, messageId: 'unsafeToUnconstrainedTypeAssertion', }, ],