Skip to main content

restrict-template-expressions

Enforce template literal expressions to be of string type.

💭

This rule requires type information to run.

JavaScript automatically converts an object to a string in a string context, such as when concatenating it with a string using + or embedding it in a template literal using ${}. The default toString() method of objects uses the format "[object Object]", which is often not what was intended. This rule reports on values used in a template literal string that aren't strings, optionally allowing other data types that provide useful stringification results.

note

The default settings of this rule intentionally do not allow objects with a custom toString() method to be used in template literals, because the stringification result may not be user-friendly.

For example, arrays have a custom toString() method, which only calls join() internally, which joins the array elements with commas. This means that (1) array elements are not necessarily stringified to useful results (2) the commas don't have spaces after them, making the result not user-friendly. The best way to format arrays is to use Intl.ListFormat, which even supports adding the "and" conjunction where necessary. You must explicitly call object.toString() if you want to use this object in a template literal, or turn on the allowArray option to specifically allow arrays. The no-base-to-string rule can be used to guard this case against producing "[object Object]" by accident.

eslint.config.mjs
export default tseslint.config({
rules: {
"@typescript-eslint/restrict-template-expressions": "error"
}
});

Try this rule in the playground ↗

Examples

const arg1 = [1, 2];
const msg1 = `arg1 = ${arg1}`;

const arg2 = { name: 'Foo' };
const msg2 = `arg2 = ${arg2 || null}`;
Open in Playground

Options

This rule accepts the following options, and has more strict settings in the strict and strict-type-checked configs.

type Options = [
{
/** Types to allow in template expressions. */
allow?: (
| {
from: 'file';
name: [string, ...string[]] | string;
path?: string;
}
| {
from: 'lib';
name: [string, ...string[]] | string;
}
| {
from: 'package';
name: [string, ...string[]] | string;
package: string;
}
| string
)[];
/** Whether to allow `any` typed values in template expressions. */
allowAny?: boolean;
/** Whether to allow `array` typed values in template expressions. */
allowArray?: boolean;
/** Whether to allow `boolean` typed values in template expressions. */
allowBoolean?: boolean;
/** Whether to allow `never` typed values in template expressions. */
allowNever?: boolean;
/** Whether to allow `nullish` typed values in template expressions. */
allowNullish?: boolean;
/** Whether to allow `number` typed values in template expressions. */
allowNumber?: boolean;
/** Whether to allow `regexp` typed values in template expressions. */
allowRegExp?: boolean;
},
];

const defaultOptionsRecommended: Options = [
{
allow: [{ name: ['Error', 'URL', 'URLSearchParams'], from: 'lib' }],
allowAny: true,
allowBoolean: true,
allowNullish: true,
allowNumber: true,
allowRegExp: true,
},
];

// These options are merged on top of the recommended defaults
const defaultOptionsStrict: Options = [
{
allowAny: false,
allowBoolean: false,
allowNever: false,
allowNullish: false,
allowNumber: false,
allowRegExp: false,
},
];

allowNumber

Whether to allow number typed values in template expressions. Default: true.

Examples of additional correct code for this rule with { allowNumber: true }:

const arg = 123;
const msg1 = `arg = ${arg}`;
const msg2 = `arg = ${arg || 'zero'}`;
Open in Playground

This option controls both numbers and BigInts.

We recommend avoiding using this option if you use any floating point numbers. Although `${1}` evaluates to '1', `${0.1 + 0.2}` evaluates to '0.30000000000000004'. Consider using .toFixed() or .toPrecision() instead.

allowBoolean

Whether to allow boolean typed values in template expressions. Default: true.

Examples of additional correct code for this rule with { allowBoolean: true }:

const arg = true;
const msg1 = `arg = ${arg}`;
const msg2 = `arg = ${arg || 'not truthy'}`;
Open in Playground

allowAny

Whether to allow any typed values in template expressions. Default: true.

Examples of additional correct code for this rule with { allowAny: true }:

const user = JSON.parse('{ "name": "foo" }');
const msg1 = `arg = ${user.name}`;
const msg2 = `arg = ${user.name || 'the user with no name'}`;
Open in Playground

allowNullish

Whether to allow nullish typed values in template expressions. Default: true.

Examples of additional correct code for this rule with { allowNullish: true }:

const arg = condition ? 'ok' : null;
const msg1 = `arg = ${arg}`;
Open in Playground

allowRegExp

Whether to allow regexp typed values in template expressions. Default: true.

Examples of additional correct code for this rule with { allowRegExp: true }:

const arg = new RegExp('foo');
const msg1 = `arg = ${arg}`;
Open in Playground
const arg = /foo/;
const msg1 = `arg = ${arg}`;
Open in Playground

allowNever

Whether to allow never typed values in template expressions. Default: false.

Examples of additional correct code for this rule with { allowNever: true }:

const arg = 'something';
const msg1 = typeof arg === 'string' ? arg : `arg = ${arg}`;
Open in Playground

allowArray

Whether to allow array typed values in template expressions. Default: false.

Examples of additional correct code for this rule with { allowArray: true }:

const arg = ['foo', 'bar'];
const msg1 = `arg = ${arg}`;
Open in Playground

allow

Types to allow in template expressions. Default: [{"name":["Error","URL","URLSearchParams"],"from":"lib"}].

Whether to allow additional types in template expressions.

This option takes the shared TypeOrValueSpecifier format.

Examples of additional correct code for this rule with the default option { allow: [{ from: 'lib', name: 'Error' }, { from: 'lib', name: 'URL' }, { from: 'lib', name: 'URLSearchParams' }] }:

const error = new Error();
const msg1 = `arg = ${error}`;
Open in Playground

When Not To Use It

If you're not worried about incorrectly stringifying non-string values in template literals, then you likely don't need this rule.


Type checked lint rules are more powerful than traditional lint rules, but also require configuring type checked linting.

See Troubleshooting > Linting with Type Information > Performance if you experience performance degradations after enabling type checked rules.

Resources