diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts index 151318e7f9bf..fdb957b4602e 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts @@ -108,10 +108,23 @@ export default createRule({ ); } - function isConstVariableDeclaration(node: TSESTree.Node): boolean { + function isLiteralVariableDeclarationChangingTypeWithConst( + node: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion, + ): boolean { + /** + * If the type assertion is on a template literal WITH expressions we + * should keep the `const` casting + * @see https://github.com/typescript-eslint/typescript-eslint/issues/8737 + */ + if (node.expression.type === AST_NODE_TYPES.TemplateLiteral) { + return node.expression.expressions.length === 0; + } + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const maybeDeclarationNode = node.parent.parent!; return ( - node.type === AST_NODE_TYPES.VariableDeclaration && - node.kind === 'const' + maybeDeclarationNode.type === AST_NODE_TYPES.VariableDeclaration && + maybeDeclarationNode.kind === 'const' ); } @@ -222,8 +235,7 @@ export default createRule({ const typeIsUnchanged = uncastType === castType; const wouldSameTypeBeInferred = castType.isLiteral() - ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - isConstVariableDeclaration(node.parent.parent!) + ? isLiteralVariableDeclarationChangingTypeWithConst(node) : !isConstAssertion(node.typeAnnotation); if (typeIsUnchanged && wouldSameTypeBeInferred) { diff --git a/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts index cde4f7a21659..a0dd0755239e 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts @@ -277,9 +277,25 @@ function bar(items: string[]) { `, parserOptions: optionsWithOnUncheckedIndexedAccess, }, + // https://github.com/typescript-eslint/typescript-eslint/issues/8737 + ` +const myString = 'foo'; +const templateLiteral = \`\${myString}-somethingElse\` as const; + `, + // https://github.com/typescript-eslint/typescript-eslint/issues/8737 + ` +const myString = 'foo'; +const templateLiteral = \`\${myString}-somethingElse\`; + `, ], invalid: [ + // https://github.com/typescript-eslint/typescript-eslint/issues/8737 + { + code: 'const a = `a` as const;', + output: 'const a = `a`;', + errors: [{ messageId: 'unnecessaryAssertion', line: 1 }], + }, { code: "const a = 'a' as const;", output: "const a = 'a';",