Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/comparisons/src/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -18152,7 +18152,8 @@
"flint": {
"name": "unnecessaryTemplateExpressions",
"plugin": "ts",
"preset": "logical"
"preset": "logical",
"status": "implemented"
},
"oxlint": [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
description: "Reports template expressions that can be replaced with simpler expressions."
title: "unnecessaryTemplateExpressions"
topic: "rules"
---

import { Tabs, TabItem } from "@astrojs/starlight/components";
import { RuleEquivalents } from "~/components/RuleEquivalents";
import RuleSummary from "~/components/RuleSummary.astro";

<RuleSummary plugin="ts" rule="unnecessaryTemplateExpressions" />

Template literals with a single substitution and no surrounding text are unnecessarily complex.
Using the expression directly is clearer and more maintainable.

For example, `` `${value}` `` is functionally equivalent to `String(value)` but adds unnecessary syntax noise.
Template literals should be reserved for cases where they provide clear value, such as embedding expressions within text or combining multiple values.

## Examples

<Tabs>
<TabItem label="❌ Incorrect">

```ts
const name = "Alice";
const greeting = `${name}`;
```

```ts
const count = 42;
const message = `${count}`;
```

```ts
function getValue() {
return "result";
}
const output = `${getValue()}`;
```

```ts
const isActive = true;
const status = `${isActive}`;
```

</TabItem>
<TabItem label="✅ Correct">

```ts
const name = "Alice";
const greeting = `Hello, ${name}!`;
```

```ts
const first = "Banana";
const last = "Cherry";
const full = `${first} ${last}`;
```

```ts
const count = 42;
const message = `Count: ${count}`;
```

```ts
const name = "Alice";
const greeting = name;
```

```ts
const count = 42;
const countString = String(count);
```

</TabItem>
</Tabs>

## Options

This rule is not configurable.

## When Not To Use It

If you have a coding standard that requires explicit string coercion using template literals for clarity or consistency, you might choose to disable this rule.
However, in most cases, removing unnecessary template wrappers improves code readability.

## Further Reading

- [MDN: Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals)
- [MDN: String coercion](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#string_coercion)

## Equivalents in Other Linters

<RuleEquivalents pluginId="ts" ruleId="unnecessaryTemplateExpressions" />
2 changes: 2 additions & 0 deletions packages/ts/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ import unnecessaryBooleanCasts from "./rules/unnecessaryBooleanCasts.ts";
import unnecessaryCatches from "./rules/unnecessaryCatches.ts";
import unnecessaryComparisons from "./rules/unnecessaryComparisons.ts";
import unnecessaryConcatenation from "./rules/unnecessaryConcatenation.ts";
import unnecessaryTemplateExpressions from "./rules/unnecessaryTemplateExpressions.ts";
import unsafeNegations from "./rules/unsafeNegations.ts";
import variableDeletions from "./rules/variableDeletions.ts";
import voidOperator from "./rules/voidOperator.ts";
Expand Down Expand Up @@ -576,6 +577,7 @@ export const ts = createPlugin({
unnecessaryCatches,
unnecessaryComparisons,
unnecessaryConcatenation,
unnecessaryTemplateExpressions,
unsafeNegations,
variableDeletions,
voidOperator,
Expand Down
76 changes: 76 additions & 0 deletions packages/ts/src/rules/unnecessaryTemplateExpressions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { ruleTester } from "./ruleTester.ts";
import rule from "./unnecessaryTemplateExpressions.ts";

ruleTester.describe(rule, {
invalid: [
{
code: `
const value = "test";
const result = \`\${value}\`;
`,
snapshot: `
const value = "test";
const result = \`\${value}\`;
~
This template expression can be replaced with a simpler expression.
`,
},
{
code: `
const count = 42;
const message = \`\${count}\`;
`,
snapshot: `
const count = 42;
const message = \`\${count}\`;
~
This template expression can be replaced with a simpler expression.
`,
},
{
code: `
function getValue() {
return "result";
}
const output = \`\${getValue()}\`;
`,
snapshot: `
function getValue() {
return "result";
}
const output = \`\${getValue()}\`;
~
This template expression can be replaced with a simpler expression.
`,
},
{
code: `
const identifier = true;
const text = \`\${identifier}\`;
`,
snapshot: `
const identifier = true;
const text = \`\${identifier}\`;
~
This template expression can be replaced with a simpler expression.
`,
},
],
valid: [
`const message = \`Hello \${name}\`;`,
`const message = \`\${firstName} \${lastName}\`;`,
`const message = \`Value: \${value}\`;`,
`const message = \`\${value} is the result\`;`,
`const plain = "just a string";`,
`const plain = \`just a template\`;`,
`
const name = "World";
const greeting = \`Hello \${name}!\`;
`,
`
const first = "Apple";
const last = "Banana";
const full = \`\${first} \${last}\`;
`,
],
});
Loading