diff --git a/packages/eslint-plugin/docs/rules/no-throw-literal.mdx b/packages/eslint-plugin/docs/rules/no-throw-literal.mdx
index d5919b3bdc63..9bd9481ffa15 100644
--- a/packages/eslint-plugin/docs/rules/no-throw-literal.mdx
+++ b/packages/eslint-plugin/docs/rules/no-throw-literal.mdx
@@ -16,10 +16,10 @@ This rule restricts what can be thrown as an exception.
:::warning
This rule is being renamed to [`only-throw-error`](./only-throw-error.mdx).
-When it was first created, it only prevented literals from being thrown (hence the name), but it has now been expanded to only allow expressions which have a possibility of being an `Error` object.
-With the `allowThrowingAny` and `allowThrowingUnknown` options, it can be configured to only allow throwing values which are guaranteed to be an instance of `Error`.
+The current name, `no-throw-literal`, will be removed in a future major version of typescript-eslint.
-The current name `no-throw-literal` will be removed in a future major version of typescript-eslint.
+When it was first created, this rule only prevented literals from being thrown (hence the name), but it has now been expanded to only allow expressions which have a possibility of being an `Error` object.
+With the `allowThrowingAny` and `allowThrowingUnknown` options, it can be configured to only allow throwing values which are guaranteed to be an instance of `Error`.
:::
{/* Intentionally Omitted: When Not To Use It */}
diff --git a/packages/eslint-plugin/docs/rules/no-useless-template-expression.mdx b/packages/eslint-plugin/docs/rules/no-useless-template-expression.mdx
new file mode 100644
index 000000000000..2b6a28802b22
--- /dev/null
+++ b/packages/eslint-plugin/docs/rules/no-useless-template-expression.mdx
@@ -0,0 +1,87 @@
+---
+description: 'Disallow unnecessary template expressions.'
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+> 🛑 This file is source code, not the primary documentation location! 🛑
+>
+> See **https://typescript-eslint.io/rules/no-useless-template-expression** for documentation.
+
+This rule reports template literals that contain substitution expressions (also variously referred to as embedded expressions or string interpolations) that are unnecessary and can be simplified.
+
+:::info[Migration from `no-useless-template-literals`]
+
+This rule was formerly known as [`no-useless-template-literals`](./no-useless-template-literals.mdx).
+We encourage users to migrate to the new name, `no-useless-template-expression`, as the old name will be removed in a future major version of typescript-eslint.
+
+The new name is a drop-in replacement with identical functionality.
+
+:::
+
+## Examples
+
+
+
+
+```ts
+// Static values can be incorporated into the surrounding template.
+
+const ab1 = `${'a'}${'b'}`;
+const ab2 = `a${'b'}`;
+
+const stringWithNumber = `${'1 + 1 = '}${2}`;
+
+const stringWithBoolean = `${'true is '}${true}`;
+
+// Some simple expressions that are already strings
+// can be rewritten without a template at all.
+
+const text = 'a';
+const wrappedText = `${text}`;
+
+declare const intersectionWithString: string & { _brand: 'test-brand' };
+const wrappedIntersection = `${intersectionWithString}`;
+```
+
+
+
+
+```ts
+// Static values can be incorporated into the surrounding template.
+
+const ab1 = `ab`;
+const ab2 = `ab`;
+
+const stringWithNumber = `1 + 1 = 2`;
+
+const stringWithBoolean = `true is true`;
+
+// Some simple expressions that are already strings
+// can be rewritten without a template at all.
+
+const text = 'a';
+const wrappedText = text;
+
+declare const intersectionWithString: string & { _brand: 'test-brand' };
+const wrappedIntersection = intersectionWithString;
+```
+
+
+
+
+:::info
+This rule does not aim to flag template literals without substitution expressions that could have been written as an ordinary string.
+That is to say, this rule will not help you turn `` `this` `` into `"this"`.
+If you are looking for such a rule, you can configure the [`@stylistic/ts/quotes`](https://eslint.style/rules/ts/quotes) rule to do this.
+:::
+
+## When Not To Use It
+
+When you want to allow string expressions inside template literals.
+
+## Related To
+
+- [`restrict-template-expressions`](./restrict-template-expressions.mdx)
+- [`@stylistic/ts/quotes`](https://eslint.style/rules/ts/quotes)
diff --git a/packages/eslint-plugin/docs/rules/no-useless-template-literals.mdx b/packages/eslint-plugin/docs/rules/no-useless-template-literals.mdx
index b229a4b1ff67..f02ec5ada9ec 100644
--- a/packages/eslint-plugin/docs/rules/no-useless-template-literals.mdx
+++ b/packages/eslint-plugin/docs/rules/no-useless-template-literals.mdx
@@ -1,5 +1,5 @@
---
-description: 'Disallow unnecessary template literals.'
+description: 'Disallow unnecessary template expressions.'
---
import Tabs from '@theme/Tabs';
@@ -9,53 +9,15 @@ import TabItem from '@theme/TabItem';
>
> See **https://typescript-eslint.io/rules/no-useless-template-literals** for documentation.
-This rule reports template literals that can be simplified to a normal string literal.
+This rule reports template literals that contain substitution expressions (also variously referred to as embedded expressions or string interpolations) that are unnecessary and can be simplified.
-## Examples
+:::warning
+This rule is being renamed to [`no-useless-template-expression`](./no-useless-template-expression.mdx).
+The current name, `no-useless-template-literals`, will be removed in a future major version of typescript-eslint.
-
-
+After the creation of this rule, it was realized that the name `no-useless-template-literals` could be misleading, seeing as this rule only targets template literals with substitution expressions.
+In particular, it does _not_ aim to flag useless template literals that look like `` `this` `` and could be simplified to `"this"`.
+If you are looking for such a rule, you can configure the [`@stylistic/ts/quotes`](https://eslint.style/rules/ts/quotes) rule to do this.
+:::
-```ts
-const ab1 = `${'a'}${'b'}`;
-const ab2 = `a${'b'}`;
-
-const stringWithNumber = `${'1 + 1 = '}${2}`;
-
-const stringWithBoolean = `${'true is '}${true}`;
-
-const text = 'a';
-const wrappedText = `${text}`;
-
-declare const intersectionWithString: string & { _brand: 'test-brand' };
-const wrappedIntersection = `${intersectionWithString}`;
-```
-
-
-
-
-```ts
-const ab1 = 'ab';
-const ab2 = 'ab';
-
-const stringWithNumber = `1 + 1 = 2`;
-
-const stringWithBoolean = `true is true`;
-
-const text = 'a';
-const wrappedText = text;
-
-declare const intersectionWithString: string & { _brand: 'test-brand' };
-const wrappedIntersection = intersectionWithString;
-```
-
-
-
-
-## When Not To Use It
-
-When you want to allow string expressions inside template literals.
-
-## Related To
-
-- [`restrict-template-expressions`](./restrict-template-expressions.mdx)
+{/* Intentionally Omitted: When Not To Use It */}
diff --git a/packages/eslint-plugin/docs/rules/only-throw-error.mdx b/packages/eslint-plugin/docs/rules/only-throw-error.mdx
index cd27f8cc4387..0070d648a888 100644
--- a/packages/eslint-plugin/docs/rules/only-throw-error.mdx
+++ b/packages/eslint-plugin/docs/rules/only-throw-error.mdx
@@ -14,6 +14,15 @@ The fundamental benefit of `Error` objects is that they automatically keep track
This rule restricts what can be thrown as an exception.
+:::info[Migration from `no-throw-literal`]
+
+This rule was formerly known as [`no-throw-literal`](./no-throw-literal.mdx).
+We encourage users to migrate to the new name, `only-throw-error`, as the old name will be removed in a future major version of typescript-eslint.
+
+The new name is a drop-in replacement with identical functionality.
+
+:::
+
## Examples
This rule is aimed at maintaining consistency when throwing exception by disallowing to throw literals and other expressions which cannot possibly be an `Error` object.
diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts
index 1e7304e45a36..ce40957c831d 100644
--- a/packages/eslint-plugin/src/configs/all.ts
+++ b/packages/eslint-plugin/src/configs/all.ts
@@ -113,7 +113,7 @@ export = {
'no-useless-constructor': 'off',
'@typescript-eslint/no-useless-constructor': 'error',
'@typescript-eslint/no-useless-empty-export': 'error',
- '@typescript-eslint/no-useless-template-literals': 'error',
+ '@typescript-eslint/no-useless-template-expression': 'error',
'@typescript-eslint/no-var-requires': 'error',
'@typescript-eslint/non-nullable-type-assertion-style': 'error',
'no-throw-literal': 'off',
diff --git a/packages/eslint-plugin/src/configs/disable-type-checked.ts b/packages/eslint-plugin/src/configs/disable-type-checked.ts
index fd3a8c2d7cbd..6400ad4f43ee 100644
--- a/packages/eslint-plugin/src/configs/disable-type-checked.ts
+++ b/packages/eslint-plugin/src/configs/disable-type-checked.ts
@@ -39,6 +39,7 @@ export = {
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/no-unsafe-unary-minus': 'off',
+ '@typescript-eslint/no-useless-template-expression': 'off',
'@typescript-eslint/no-useless-template-literals': 'off',
'@typescript-eslint/non-nullable-type-assertion-style': 'off',
'@typescript-eslint/only-throw-error': 'off',
diff --git a/packages/eslint-plugin/src/configs/strict-type-checked-only.ts b/packages/eslint-plugin/src/configs/strict-type-checked-only.ts
index 12709933dfb7..0815a6007e31 100644
--- a/packages/eslint-plugin/src/configs/strict-type-checked-only.ts
+++ b/packages/eslint-plugin/src/configs/strict-type-checked-only.ts
@@ -33,7 +33,7 @@ export = {
'@typescript-eslint/no-unsafe-enum-comparison': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
- '@typescript-eslint/no-useless-template-literals': 'error',
+ '@typescript-eslint/no-useless-template-expression': 'error',
'no-throw-literal': 'off',
'@typescript-eslint/only-throw-error': 'error',
'@typescript-eslint/prefer-includes': 'error',
diff --git a/packages/eslint-plugin/src/configs/strict-type-checked.ts b/packages/eslint-plugin/src/configs/strict-type-checked.ts
index 26d8d9698812..2396c00ced5e 100644
--- a/packages/eslint-plugin/src/configs/strict-type-checked.ts
+++ b/packages/eslint-plugin/src/configs/strict-type-checked.ts
@@ -60,7 +60,7 @@ export = {
'@typescript-eslint/no-unused-vars': 'error',
'no-useless-constructor': 'off',
'@typescript-eslint/no-useless-constructor': 'error',
- '@typescript-eslint/no-useless-template-literals': 'error',
+ '@typescript-eslint/no-useless-template-expression': 'error',
'@typescript-eslint/no-var-requires': 'error',
'no-throw-literal': 'off',
'@typescript-eslint/only-throw-error': 'error',
diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts
index 64c6a872ed69..9befde4df7bf 100644
--- a/packages/eslint-plugin/src/rules/index.ts
+++ b/packages/eslint-plugin/src/rules/index.ts
@@ -97,6 +97,7 @@ import noUnusedVars from './no-unused-vars';
import noUseBeforeDefine from './no-use-before-define';
import noUselessConstructor from './no-useless-constructor';
import noUselessEmptyExport from './no-useless-empty-export';
+import noUselessTemplateExpression from './no-useless-template-expression';
import noUselessTemplateLiterals from './no-useless-template-literals';
import noVarRequires from './no-var-requires';
import nonNullableTypeAssertionStyle from './non-nullable-type-assertion-style';
@@ -242,6 +243,7 @@ export default {
'no-use-before-define': noUseBeforeDefine,
'no-useless-constructor': noUselessConstructor,
'no-useless-empty-export': noUselessEmptyExport,
+ 'no-useless-template-expression': noUselessTemplateExpression,
'no-useless-template-literals': noUselessTemplateLiterals,
'no-var-requires': noVarRequires,
'non-nullable-type-assertion-style': nonNullableTypeAssertionStyle,
diff --git a/packages/eslint-plugin/src/rules/no-useless-template-expression.ts b/packages/eslint-plugin/src/rules/no-useless-template-expression.ts
new file mode 100644
index 000000000000..e7afc261e2fe
--- /dev/null
+++ b/packages/eslint-plugin/src/rules/no-useless-template-expression.ts
@@ -0,0 +1,175 @@
+import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
+import { AST_NODE_TYPES } from '@typescript-eslint/utils';
+import * as ts from 'typescript';
+
+import {
+ createRule,
+ getConstrainedTypeAtLocation,
+ getParserServices,
+ getStaticStringValue,
+ isTypeFlagSet,
+ isUndefinedIdentifier,
+} from '../util';
+
+type MessageId = 'noUselessTemplateExpression';
+
+export default createRule<[], MessageId>({
+ name: 'no-useless-template-expression',
+ meta: {
+ fixable: 'code',
+ type: 'suggestion',
+ docs: {
+ description: 'Disallow unnecessary template expressions',
+ recommended: 'strict',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ noUselessTemplateExpression:
+ 'Template literal expression is unnecessary and can be simplified.',
+ },
+ schema: [],
+ },
+ defaultOptions: [],
+ create(context) {
+ const services = getParserServices(context);
+
+ function isUnderlyingTypeString(
+ expression: TSESTree.Expression,
+ ): expression is TSESTree.StringLiteral | TSESTree.Identifier {
+ const type = getConstrainedTypeAtLocation(services, expression);
+
+ const isString = (t: ts.Type): boolean => {
+ return isTypeFlagSet(t, ts.TypeFlags.StringLike);
+ };
+
+ if (type.isUnion()) {
+ return type.types.every(isString);
+ }
+
+ if (type.isIntersection()) {
+ return type.types.some(isString);
+ }
+
+ return isString(type);
+ }
+
+ function isLiteral(expression: TSESTree.Expression): boolean {
+ return expression.type === AST_NODE_TYPES.Literal;
+ }
+
+ function isTemplateLiteral(expression: TSESTree.Expression): boolean {
+ return expression.type === AST_NODE_TYPES.TemplateLiteral;
+ }
+
+ function isInfinityIdentifier(expression: TSESTree.Expression): boolean {
+ return (
+ expression.type === AST_NODE_TYPES.Identifier &&
+ expression.name === 'Infinity'
+ );
+ }
+
+ function isNaNIdentifier(expression: TSESTree.Expression): boolean {
+ return (
+ expression.type === AST_NODE_TYPES.Identifier &&
+ expression.name === 'NaN'
+ );
+ }
+
+ return {
+ TemplateLiteral(node: TSESTree.TemplateLiteral): void {
+ if (node.parent.type === AST_NODE_TYPES.TaggedTemplateExpression) {
+ return;
+ }
+
+ const hasSingleStringVariable =
+ node.quasis.length === 2 &&
+ node.quasis[0].value.raw === '' &&
+ node.quasis[1].value.raw === '' &&
+ node.expressions.length === 1 &&
+ isUnderlyingTypeString(node.expressions[0]);
+
+ if (hasSingleStringVariable) {
+ context.report({
+ node: node.expressions[0],
+ messageId: 'noUselessTemplateExpression',
+ fix(fixer): TSESLint.RuleFix[] {
+ const [prevQuasi, nextQuasi] = node.quasis;
+
+ // Remove the quasis and backticks.
+ return [
+ fixer.removeRange([
+ prevQuasi.range[1] - 3,
+ node.expressions[0].range[0],
+ ]),
+
+ fixer.removeRange([
+ node.expressions[0].range[1],
+ nextQuasi.range[0] + 2,
+ ]),
+ ];
+ },
+ });
+
+ return;
+ }
+
+ const fixableExpressions = node.expressions.filter(
+ expression =>
+ isLiteral(expression) ||
+ isTemplateLiteral(expression) ||
+ isUndefinedIdentifier(expression) ||
+ isInfinityIdentifier(expression) ||
+ isNaNIdentifier(expression),
+ );
+
+ fixableExpressions.forEach(expression => {
+ context.report({
+ node: expression,
+ messageId: 'noUselessTemplateExpression',
+ fix(fixer): TSESLint.RuleFix[] {
+ const index = node.expressions.indexOf(expression);
+ const prevQuasi = node.quasis[index];
+ const nextQuasi = node.quasis[index + 1];
+
+ // Remove the quasis' parts that are related to the current expression.
+ const fixes = [
+ fixer.removeRange([
+ prevQuasi.range[1] - 2,
+ expression.range[0],
+ ]),
+
+ fixer.removeRange([
+ expression.range[1],
+ nextQuasi.range[0] + 1,
+ ]),
+ ];
+
+ const stringValue = getStaticStringValue(expression);
+
+ if (stringValue != null) {
+ const escapedValue = stringValue.replace(/([`$\\])/g, '\\$1');
+
+ fixes.push(fixer.replaceText(expression, escapedValue));
+ } else if (isTemplateLiteral(expression)) {
+ // Note that some template literals get handled in the previous branch too.
+ // Remove the beginning and trailing backtick characters.
+ fixes.push(
+ fixer.removeRange([
+ expression.range[0],
+ expression.range[0] + 1,
+ ]),
+ fixer.removeRange([
+ expression.range[1] - 1,
+ expression.range[1],
+ ]),
+ );
+ }
+
+ return fixes;
+ },
+ });
+ });
+ },
+ };
+ },
+});
diff --git a/packages/eslint-plugin/src/rules/no-useless-template-literals.ts b/packages/eslint-plugin/src/rules/no-useless-template-literals.ts
index 4610d406465a..9156c6e4053e 100644
--- a/packages/eslint-plugin/src/rules/no-useless-template-literals.ts
+++ b/packages/eslint-plugin/src/rules/no-useless-template-literals.ts
@@ -11,7 +11,7 @@ import {
isUndefinedIdentifier,
} from '../util';
-type MessageId = 'noUselessTemplateLiteral';
+type MessageId = 'noUselessTemplateExpression';
export default createRule<[], MessageId>({
name: 'no-useless-template-literals',
@@ -19,15 +19,16 @@ export default createRule<[], MessageId>({
fixable: 'code',
type: 'suggestion',
docs: {
- description: 'Disallow unnecessary template literals',
- recommended: 'strict',
+ description: 'Disallow unnecessary template expressions',
requiresTypeChecking: true,
},
messages: {
- noUselessTemplateLiteral:
+ noUselessTemplateExpression:
'Template literal expression is unnecessary and can be simplified.',
},
schema: [],
+ deprecated: true,
+ replacedBy: ['@typescript-eslint/no-useless-template-expression'],
},
defaultOptions: [],
create(context) {
@@ -91,7 +92,7 @@ export default createRule<[], MessageId>({
if (hasSingleStringVariable) {
context.report({
node: node.expressions[0],
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
fix(fixer): TSESLint.RuleFix[] {
const [prevQuasi, nextQuasi] = node.quasis;
@@ -125,7 +126,7 @@ export default createRule<[], MessageId>({
fixableExpressions.forEach(expression => {
context.report({
node: expression,
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
fix(fixer): TSESLint.RuleFix[] {
const index = node.expressions.indexOf(expression);
const prevQuasi = node.quasis[index];
diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-useless-template-expression.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-useless-template-expression.shot
new file mode 100644
index 000000000000..d5813404d862
--- /dev/null
+++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-useless-template-expression.shot
@@ -0,0 +1,56 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Validating rule docs no-useless-template-expression.mdx code examples ESLint output 1`] = `
+"Incorrect
+
+// Static values can be incorporated into the surrounding template.
+
+const ab1 = \`\${'a'}\${'b'}\`;
+ ~~~ Template literal expression is unnecessary and can be simplified.
+ ~~~ Template literal expression is unnecessary and can be simplified.
+const ab2 = \`a\${'b'}\`;
+ ~~~ Template literal expression is unnecessary and can be simplified.
+
+const stringWithNumber = \`\${'1 + 1 = '}\${2}\`;
+ ~~~~~~~~~~ Template literal expression is unnecessary and can be simplified.
+ ~ Template literal expression is unnecessary and can be simplified.
+
+const stringWithBoolean = \`\${'true is '}\${true}\`;
+ ~~~~~~~~~~ Template literal expression is unnecessary and can be simplified.
+ ~~~~ Template literal expression is unnecessary and can be simplified.
+
+// Some simple expressions that are already strings
+// can be rewritten without a template at all.
+
+const text = 'a';
+const wrappedText = \`\${text}\`;
+ ~~~~ Template literal expression is unnecessary and can be simplified.
+
+declare const intersectionWithString: string & { _brand: 'test-brand' };
+const wrappedIntersection = \`\${intersectionWithString}\`;
+ ~~~~~~~~~~~~~~~~~~~~~~ Template literal expression is unnecessary and can be simplified.
+"
+`;
+
+exports[`Validating rule docs no-useless-template-expression.mdx code examples ESLint output 2`] = `
+"Correct
+
+// Static values can be incorporated into the surrounding template.
+
+const ab1 = \`ab\`;
+const ab2 = \`ab\`;
+
+const stringWithNumber = \`1 + 1 = 2\`;
+
+const stringWithBoolean = \`true is true\`;
+
+// Some simple expressions that are already strings
+// can be rewritten without a template at all.
+
+const text = 'a';
+const wrappedText = text;
+
+declare const intersectionWithString: string & { _brand: 'test-brand' };
+const wrappedIntersection = intersectionWithString;
+"
+`;
diff --git a/packages/eslint-plugin/tests/rules/no-useless-template-expression.test.ts b/packages/eslint-plugin/tests/rules/no-useless-template-expression.test.ts
new file mode 100644
index 000000000000..628057ac7d17
--- /dev/null
+++ b/packages/eslint-plugin/tests/rules/no-useless-template-expression.test.ts
@@ -0,0 +1,641 @@
+import { noFormat, RuleTester } from '@typescript-eslint/rule-tester';
+
+import rule from '../../src/rules/no-useless-template-expression';
+import { getFixturesRootDir } from '../RuleTester';
+
+const rootPath = getFixturesRootDir();
+
+const ruleTester = new RuleTester({
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ tsconfigRootDir: rootPath,
+ project: './tsconfig.json',
+ },
+});
+
+ruleTester.run('no-useless-template-expression', rule, {
+ valid: [
+ "const string = 'a';",
+ 'const string = `a`;',
+ `
+ declare const string: 'a';
+ \`\${string}b\`;
+ `,
+
+ `
+ declare const number: 1;
+ \`\${number}b\`;
+ `,
+
+ `
+ declare const boolean: true;
+ \`\${boolean}b\`;
+ `,
+
+ `
+ declare const nullish: null;
+ \`\${nullish}-undefined\`;
+ `,
+
+ `
+ declare const undefinedish: undefined;
+ \`\${undefinedish}\`;
+ `,
+
+ `
+ declare const left: 'a';
+ declare const right: 'b';
+ \`\${left}\${right}\`;
+ `,
+
+ `
+ declare const left: 'a';
+ declare const right: 'c';
+ \`\${left}b\${right}\`;
+ `,
+
+ `
+ declare const left: 'a';
+ declare const center: 'b';
+ declare const right: 'c';
+ \`\${left}\${center}\${right}\`;
+ `,
+
+ '`1 + 1 = ${1 + 1}`;',
+
+ '`true && false = ${true && false}`;',
+
+ "tag`${'a'}${'b'}`;",
+
+ '`${function () {}}`;',
+
+ '`${() => {}}`;',
+
+ '`${(...args: any[]) => args}`;',
+
+ `
+ declare const number: 1;
+ \`\${number}\`;
+ `,
+
+ `
+ declare const boolean: true;
+ \`\${boolean}\`;
+ `,
+
+ `
+ declare const nullish: null;
+ \`\${nullish}\`;
+ `,
+
+ `
+ declare const union: string | number;
+ \`\${union}\`;
+ `,
+
+ `
+ declare const unknown: unknown;
+ \`\${unknown}\`;
+ `,
+
+ `
+ declare const never: never;
+ \`\${never}\`;
+ `,
+
+ `
+ declare const any: any;
+ \`\${any}\`;
+ `,
+
+ `
+ function func(arg: T) {
+ \`\${arg}\`;
+ }
+ `,
+
+ `
+ \`with
+
+ new line\`;
+ `,
+
+ `
+ declare const a: 'a';
+
+ \`\${a} with
+
+ new line\`;
+ `,
+
+ noFormat`
+ \`with windows \r new line\`;
+ `,
+
+ `
+\`not a useless \${String.raw\`nested interpolation \${a}\`}\`;
+ `,
+ ],
+
+ invalid: [
+ {
+ code: '`${1}`;',
+ output: '`1`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 4,
+ endColumn: 5,
+ },
+ ],
+ },
+ {
+ code: '`${1n}`;',
+ output: '`1`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 4,
+ endColumn: 6,
+ },
+ ],
+ },
+ {
+ code: '`${/a/}`;',
+ output: '`/a/`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 4,
+ endColumn: 7,
+ },
+ ],
+ },
+
+ {
+ code: noFormat`\`\${ 1 }\`;`,
+ output: '`1`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: noFormat`\`\${ 'a' }\`;`,
+ output: `'a';`,
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: noFormat`\`\${ "a" }\`;`,
+ output: `"a";`,
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: noFormat`\`\${ 'a' + 'b' }\`;`,
+ output: `'a' + 'b';`,
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: '`${true}`;',
+ output: '`true`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 4,
+ endColumn: 8,
+ },
+ ],
+ },
+
+ {
+ code: noFormat`\`\${ true }\`;`,
+ output: '`true`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: '`${null}`;',
+ output: '`null`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 4,
+ endColumn: 8,
+ },
+ ],
+ },
+
+ {
+ code: noFormat`\`\${ null }\`;`,
+ output: '`null`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: '`${undefined}`;',
+ output: '`undefined`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 4,
+ endColumn: 13,
+ },
+ ],
+ },
+
+ {
+ code: noFormat`\`\${ undefined }\`;`,
+ output: '`undefined`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: '`${Infinity}`;',
+ output: '`Infinity`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 4,
+ endColumn: 12,
+ },
+ ],
+ },
+
+ {
+ code: '`${NaN}`;',
+ output: '`NaN`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 4,
+ endColumn: 7,
+ },
+ ],
+ },
+
+ {
+ code: "`${'a'} ${'b'}`;",
+ output: '`a b`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 4,
+ endColumn: 7,
+ },
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 11,
+ endColumn: 14,
+ },
+ ],
+ },
+
+ {
+ code: noFormat`\`\${ 'a' } \${ 'b' }\`;`,
+ output: '`a b`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: `
+ declare const b: 'b';
+ \`a\${b}\${'c'}\`;
+ `,
+ output: `
+ declare const b: 'b';
+ \`a\${b}c\`;
+ `,
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 3,
+ column: 17,
+ endColumn: 20,
+ },
+ ],
+ },
+
+ {
+ code: "`use${'less'}`;",
+ output: '`useless`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ },
+ ],
+ },
+
+ {
+ code: '`use${`less`}`;',
+ output: '`useless`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ },
+ ],
+ },
+
+ {
+ code: `
+declare const nested: string, interpolation: string;
+\`use\${\`less\${nested}\${interpolation}\`}\`;
+ `,
+ output: `
+declare const nested: string, interpolation: string;
+\`useless\${nested}\${interpolation}\`;
+ `,
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: noFormat`
+\`u\${
+ // hopefully this comment is not needed.
+ 'se'
+
+}\${
+ \`le\${ \`ss\` }\`
+}\`;
+ `,
+ output: `
+\`use\${
+ \`less\`
+}\`;
+ `,
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 4,
+ },
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 7,
+ column: 3,
+ endLine: 7,
+ },
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 7,
+ column: 10,
+ endLine: 7,
+ },
+ ],
+ },
+ {
+ code: noFormat`
+\`use\${
+ \`less\`
+}\`;
+ `,
+ output: `
+\`useless\`;
+ `,
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 3,
+ column: 3,
+ endColumn: 9,
+ },
+ ],
+ },
+
+ {
+ code: "`${'1 + 1 ='} ${2}`;",
+ output: '`1 + 1 = 2`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 4,
+ endColumn: 13,
+ },
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 17,
+ endColumn: 18,
+ },
+ ],
+ },
+
+ {
+ code: "`${'a'} ${true}`;",
+ output: '`a true`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 4,
+ endColumn: 7,
+ },
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 11,
+ endColumn: 15,
+ },
+ ],
+ },
+
+ {
+ code: `
+ declare const string: 'a';
+ \`\${string}\`;
+ `,
+ output: `
+ declare const string: 'a';
+ string;
+ `,
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 3,
+ column: 12,
+ endColumn: 18,
+ },
+ ],
+ },
+
+ {
+ code: noFormat`
+ declare const string: 'a';
+ \`\${ string }\`;
+ `,
+ output: `
+ declare const string: 'a';
+ string;
+ `,
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: "`${String(Symbol.for('test'))}`;",
+ output: "String(Symbol.for('test'));",
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 1,
+ column: 4,
+ endColumn: 30,
+ },
+ ],
+ },
+
+ {
+ code: `
+ declare const intersection: string & { _brand: 'test-brand' };
+ \`\${intersection}\`;
+ `,
+ output: `
+ declare const intersection: string & { _brand: 'test-brand' };
+ intersection;
+ `,
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 3,
+ column: 12,
+ endColumn: 24,
+ },
+ ],
+ },
+
+ {
+ code: `
+ function func(arg: T) {
+ \`\${arg}\`;
+ }
+ `,
+ output: `
+ function func(arg: T) {
+ arg;
+ }
+ `,
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ line: 3,
+ column: 14,
+ endColumn: 17,
+ },
+ ],
+ },
+
+ {
+ code: "`${'`'}`;",
+ output: "'`';",
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: "`back${'`'}tick`;",
+ output: '`back\\`tick`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: "`dollar${'${`this is test`}'}sign`;",
+ output: '`dollar\\${\\`this is test\\`}sign`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: '`complex${\'`${"`${test}`"}`\'}case`;',
+ output: '`complex\\`\\${"\\`\\${test}\\`"}\\`case`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: "`some ${'\\\\${test}'} string`;",
+ output: '`some \\\\\\${test} string`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+
+ {
+ code: "`some ${'\\\\`'} string`;",
+ output: '`some \\\\\\` string`;',
+ errors: [
+ {
+ messageId: 'noUselessTemplateExpression',
+ },
+ ],
+ },
+ ],
+});
diff --git a/packages/eslint-plugin/tests/rules/no-useless-template-literals.test.ts b/packages/eslint-plugin/tests/rules/no-useless-template-literals.test.ts
index d443c4ff729d..06eacb1e31e6 100644
--- a/packages/eslint-plugin/tests/rules/no-useless-template-literals.test.ts
+++ b/packages/eslint-plugin/tests/rules/no-useless-template-literals.test.ts
@@ -143,7 +143,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`1`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 4,
endColumn: 5,
@@ -155,7 +155,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`1`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 4,
endColumn: 6,
@@ -167,7 +167,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`/a/`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 4,
endColumn: 7,
@@ -180,7 +180,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`1`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -190,7 +190,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: `'a';`,
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -200,7 +200,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: `"a";`,
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -210,7 +210,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: `'a' + 'b';`,
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -220,7 +220,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`true`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 4,
endColumn: 8,
@@ -233,7 +233,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`true`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -243,7 +243,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`null`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 4,
endColumn: 8,
@@ -256,7 +256,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`null`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -266,7 +266,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`undefined`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 4,
endColumn: 13,
@@ -279,7 +279,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`undefined`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -289,7 +289,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`Infinity`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 4,
endColumn: 12,
@@ -302,7 +302,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`NaN`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 4,
endColumn: 7,
@@ -315,13 +315,13 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`a b`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 4,
endColumn: 7,
},
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 11,
endColumn: 14,
@@ -334,10 +334,10 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`a b`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -353,7 +353,7 @@ ruleTester.run('no-useless-template-literals', rule, {
`,
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 3,
column: 17,
endColumn: 20,
@@ -366,7 +366,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`useless`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
},
],
@@ -377,7 +377,7 @@ ruleTester.run('no-useless-template-literals', rule, {
output: '`useless`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
},
],
@@ -394,7 +394,7 @@ declare const nested: string, interpolation: string;
`,
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -416,17 +416,17 @@ declare const nested: string, interpolation: string;
`,
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 4,
},
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 7,
column: 3,
endLine: 7,
},
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 7,
column: 10,
endLine: 7,
@@ -444,7 +444,7 @@ declare const nested: string, interpolation: string;
`,
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 3,
column: 3,
endColumn: 9,
@@ -457,13 +457,13 @@ declare const nested: string, interpolation: string;
output: '`1 + 1 = 2`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 4,
endColumn: 13,
},
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 17,
endColumn: 18,
@@ -476,13 +476,13 @@ declare const nested: string, interpolation: string;
output: '`a true`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 4,
endColumn: 7,
},
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 11,
endColumn: 15,
@@ -501,7 +501,7 @@ declare const nested: string, interpolation: string;
`,
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 3,
column: 12,
endColumn: 18,
@@ -520,7 +520,7 @@ declare const nested: string, interpolation: string;
`,
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -530,7 +530,7 @@ declare const nested: string, interpolation: string;
output: "String(Symbol.for('test'));",
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 1,
column: 4,
endColumn: 30,
@@ -549,7 +549,7 @@ declare const nested: string, interpolation: string;
`,
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 3,
column: 12,
endColumn: 24,
@@ -570,7 +570,7 @@ declare const nested: string, interpolation: string;
`,
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
line: 3,
column: 14,
endColumn: 17,
@@ -583,7 +583,7 @@ declare const nested: string, interpolation: string;
output: "'`';",
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -593,7 +593,7 @@ declare const nested: string, interpolation: string;
output: '`back\\`tick`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -603,7 +603,7 @@ declare const nested: string, interpolation: string;
output: '`dollar\\${\\`this is test\\`}sign`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -613,7 +613,7 @@ declare const nested: string, interpolation: string;
output: '`complex\\`\\${"\\`\\${test}\\`"}\\`case`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -623,7 +623,7 @@ declare const nested: string, interpolation: string;
output: '`some \\\\\\${test} string`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
@@ -633,7 +633,7 @@ declare const nested: string, interpolation: string;
output: '`some \\\\\\` string`;',
errors: [
{
- messageId: 'noUselessTemplateLiteral',
+ messageId: 'noUselessTemplateExpression',
},
],
},
diff --git a/packages/eslint-plugin/tests/schema-snapshots/no-useless-template-expression.shot b/packages/eslint-plugin/tests/schema-snapshots/no-useless-template-expression.shot
new file mode 100644
index 000000000000..f34596f9a1a4
--- /dev/null
+++ b/packages/eslint-plugin/tests/schema-snapshots/no-useless-template-expression.shot
@@ -0,0 +1,14 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Rule schemas should be convertible to TS types for documentation purposes no-useless-template-expression 1`] = `
+"
+# SCHEMA:
+
+[]
+
+
+# TYPES:
+
+/** No options declared */
+type Options = [];"
+`;
diff --git a/packages/typescript-eslint/src/configs/all.ts b/packages/typescript-eslint/src/configs/all.ts
index efe0d16fceb8..71d701e3d1ca 100644
--- a/packages/typescript-eslint/src/configs/all.ts
+++ b/packages/typescript-eslint/src/configs/all.ts
@@ -122,7 +122,7 @@ export default (
'no-useless-constructor': 'off',
'@typescript-eslint/no-useless-constructor': 'error',
'@typescript-eslint/no-useless-empty-export': 'error',
- '@typescript-eslint/no-useless-template-literals': 'error',
+ '@typescript-eslint/no-useless-template-expression': 'error',
'@typescript-eslint/no-var-requires': 'error',
'@typescript-eslint/non-nullable-type-assertion-style': 'error',
'no-throw-literal': 'off',
diff --git a/packages/typescript-eslint/src/configs/disable-type-checked.ts b/packages/typescript-eslint/src/configs/disable-type-checked.ts
index 8d2f29220aba..9be9ab93dfd3 100644
--- a/packages/typescript-eslint/src/configs/disable-type-checked.ts
+++ b/packages/typescript-eslint/src/configs/disable-type-checked.ts
@@ -42,6 +42,7 @@ export default (
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/no-unsafe-unary-minus': 'off',
+ '@typescript-eslint/no-useless-template-expression': 'off',
'@typescript-eslint/no-useless-template-literals': 'off',
'@typescript-eslint/non-nullable-type-assertion-style': 'off',
'@typescript-eslint/only-throw-error': 'off',
diff --git a/packages/typescript-eslint/src/configs/strict-type-checked-only.ts b/packages/typescript-eslint/src/configs/strict-type-checked-only.ts
index f17b5280ca49..a2dbdaab1059 100644
--- a/packages/typescript-eslint/src/configs/strict-type-checked-only.ts
+++ b/packages/typescript-eslint/src/configs/strict-type-checked-only.ts
@@ -42,7 +42,7 @@ export default (
'@typescript-eslint/no-unsafe-enum-comparison': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
- '@typescript-eslint/no-useless-template-literals': 'error',
+ '@typescript-eslint/no-useless-template-expression': 'error',
'no-throw-literal': 'off',
'@typescript-eslint/only-throw-error': 'error',
'@typescript-eslint/prefer-includes': 'error',
diff --git a/packages/typescript-eslint/src/configs/strict-type-checked.ts b/packages/typescript-eslint/src/configs/strict-type-checked.ts
index ad62ee749e25..20db0da63d1b 100644
--- a/packages/typescript-eslint/src/configs/strict-type-checked.ts
+++ b/packages/typescript-eslint/src/configs/strict-type-checked.ts
@@ -69,7 +69,7 @@ export default (
'@typescript-eslint/no-unused-vars': 'error',
'no-useless-constructor': 'off',
'@typescript-eslint/no-useless-constructor': 'error',
- '@typescript-eslint/no-useless-template-literals': 'error',
+ '@typescript-eslint/no-useless-template-expression': 'error',
'@typescript-eslint/no-var-requires': 'error',
'no-throw-literal': 'off',
'@typescript-eslint/only-throw-error': 'error',