Skip to main content

restrict-plus-operands

Require both operands of addition to be the same type and be bigint, number, or string.

💭

This rule requires type information to run.

TypeScript allows + adding together two values of any type(s). However, adding values that are not the same type and/or are not the same primitive type is often a sign of programmer error.

This rule reports when a + operation combines two values of different types, or a type that is not bigint, number, or string.

.eslintrc.cjs
module.exports = {
"rules": {
"@typescript-eslint/restrict-plus-operands": "error"
}
};
Try this rule in the playground ↗

Examples

let foo = '5.5' + 5;
let foo = 1n + 1;
Open in Playground

Options

This rule accepts the following options

type Options = [
{
/** Whether to allow `any` typed values. */
allowAny?: boolean;
/** Whether to allow `boolean` typed values. */
allowBoolean?: boolean;
/** Whether to allow potentially `null` or `undefined` typed values. */
allowNullish?: boolean;
/** Whether to allow `bigint`/`number` typed values and `string` typed values to be added together. */
allowNumberAndString?: boolean;
/** Whether to allow `regexp` typed values. */
allowRegExp?: boolean;
/** Whether to skip compound assignments such as `+=`. */
skipCompoundAssignments?: boolean;
},
];

const defaultOptions: Options = [
{
allowAny: true,
allowBoolean: true,
allowNullish: true,
allowNumberAndString: true,
allowRegExp: true,
skipCompoundAssignments: false,
},
];
caution

We generally recommend against using these options, as they limit which varieties of incorrect + usage can be checked. This in turn severely limits the validation that the rule can do to ensure that resulting strings and numbers are correct.

Safer alternatives to using the allow* options include:

  • Using variadic forms of logging APIs to avoid needing to + values.
    console.log('The result is ' + true);
    console.log('The result is', true);
  • Using .toFixed() to coerce numbers to well-formed string representations:
    const number = 1.123456789;
    const result = 'The number is ' + number.toFixed(2);
    // result === 'The number is 1.12'
  • Calling .toString() on other types to mark explicit and intentional string coercion:
    const arg = '11';
    const regex = /[0-9]/;
    const result =
    'The result of ' +
    regex.toString() +
    '.test("' +
    arg +
    '") is ' +
    regex.test(arg).toString();
    // result === 'The result of /[0-9]/.test("11") is true'

allowAny

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

let fn = (a: number, b: []) => a + b;
let fn = (a: string, b: []) => a + b;
Open in Playground

allowBoolean

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

let fn = (a: number, b: unknown) => a + b;
let fn = (a: string, b: unknown) => a + b;
Open in Playground

allowNullish

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

let fn = (a: number, b: unknown) => a + b;
let fn = (a: number, b: never) => a + b;
let fn = (a: string, b: unknown) => a + b;
let fn = (a: string, b: never) => a + b;
Open in Playground

allowNumberAndString

Examples of code for this rule with { allowNumberAndString: true }:

let fn = (a: number, b: unknown) => a + b;
let fn = (a: number, b: never) => a + b;
Open in Playground

allowRegExp

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

let fn = (a: number, b: RegExp) => a + b;
Open in Playground

skipCompoundAssignments

Examples of code for this rule with { skipCompoundAssignments: false }:

let foo: string | undefined;
foo += 'some data';

let bar: string = '';
bar += 0;
Open in Playground

When Not To Use It

If you don't mind "[object Object]" in your strings, then you will not need this rule.

Further Reading

Resources