diff --git a/apps/oxlint/fixtures/tsgolint/no-unnecessary-template-expression.ts b/apps/oxlint/fixtures/tsgolint/no-unnecessary-template-expression.ts index 0155186c0db37..ff8d8ae694d31 100644 --- a/apps/oxlint/fixtures/tsgolint/no-unnecessary-template-expression.ts +++ b/apps/oxlint/fixtures/tsgolint/no-unnecessary-template-expression.ts @@ -1,3 +1,4 @@ -const str1 = `Hello world`; +const text = 'hello'; +const wrapped = `${text}`; export {}; \ No newline at end of file diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware --silent@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware --silent@oxlint.snap index f741c06ce2202..d46e015cad82a 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware --silent@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware --silent@oxlint.snap @@ -6,7 +6,7 @@ arguments: --type-aware --silent working directory: fixtures/tsgolint ---------- -Found 0 warnings and 50 errors. +Found 0 warnings and 51 errors. Finished in ms on 45 files using 1 threads. ---------- CLI result: LintFoundErrors diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap index a0692950c286e..7f2814f22d1f9 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap @@ -132,6 +132,14 @@ working directory: fixtures/tsgolint 3 | } `---- + x typescript-eslint(no-unnecessary-template-expression): Template literal expression is unnecessary and can be simplified. + ,-[no-unnecessary-template-expression.ts:2:18] + 1 | const text = 'hello'; + 2 | const wrapped = `${text}`; + : ^^^^^^^ + 3 | + `---- + x typescript-eslint(no-unnecessary-type-arguments): This is the default value for this type parameter, so it can be omitted. ,-[no-unnecessary-type-arguments.ts:4:25] 3 | } @@ -388,7 +396,7 @@ working directory: fixtures/tsgolint : ^^^^^^^^ `---- -Found 0 warnings and 50 errors. +Found 0 warnings and 51 errors. Finished in ms on 45 files using 1 threads. ---------- CLI result: LintFoundErrors diff --git a/crates/oxc_linter/src/rules/typescript/no_unnecessary_template_expression.rs b/crates/oxc_linter/src/rules/typescript/no_unnecessary_template_expression.rs index 2c3785cb9da5f..b0d9cd341341e 100644 --- a/crates/oxc_linter/src/rules/typescript/no_unnecessary_template_expression.rs +++ b/crates/oxc_linter/src/rules/typescript/no_unnecessary_template_expression.rs @@ -8,46 +8,57 @@ pub struct NoUnnecessaryTemplateExpression; declare_oxc_lint!( /// ### What it does /// - /// This rule disallows unnecessary template literals. + /// Disallows unnecessary template expressions (interpolations) that can be simplified. /// /// ### Why is this bad? /// - /// Template literals should only be used when they are needed for string interpolation or multi-line strings. Using template literals when a simple string would suffice adds unnecessary complexity. + /// Template literals with substitution expressions that are unnecessary add complexity + /// without providing any benefit. Static string literal expressions or expressions that + /// are already strings can be simplified. + /// + /// Note: This rule does not flag template literals without substitution expressions. + /// For example, `` `hello` `` is allowed even though it could be written as `'hello'`. /// /// ### Examples /// /// Examples of **incorrect** code for this rule: /// ```ts - /// const str1 = `Hello world`; + /// // Static values can be incorporated into the surrounding template + /// const ab1 = `${'a'}${'b'}`; + /// const ab2 = `a${'b'}`; /// - /// const str2 = `42`; + /// const stringWithNumber = `${'1 + 1 = '}${2}`; + /// const stringWithBoolean = `${'true is '}${true}`; /// - /// const str3 = `true`; + /// // Expressions that are already strings can be rewritten without a template + /// const text = 'a'; + /// const wrappedText = `${text}`; /// - /// // Template with only literal expressions - /// const str4 = `${'Hello'} ${'world'}`; + /// declare const intersectionWithString: string & { _brand: 'test-brand' }; + /// const wrappedIntersection = `${intersectionWithString}`; /// ``` /// /// Examples of **correct** code for this rule: /// ```ts - /// const str1 = 'Hello world'; + /// // Static values incorporated into the template + /// const ab1 = `ab`; /// - /// const str2 = '42'; + /// // Template with non-trivial interpolation + /// const name = 'world'; + /// const greeting = `Hello ${name}!`; /// - /// const str3 = 'true'; + /// // Template with expression + /// const result = `Result: ${1 + 2}`; /// - /// // Template with variable interpolation - /// const name = 'world'; - /// const str4 = `Hello ${name}`; + /// // Simple strings don't need templates + /// const text = 'a'; + /// const wrappedText = text; /// - /// // Multi-line string + /// // Multi-line strings are fine /// const multiline = ` /// Hello /// world /// `; - /// - /// // Template with expression - /// const str5 = `Result: ${1 + 2}`; /// ``` NoUnnecessaryTemplateExpression(tsgolint), typescript,