restrict-plus-operands
Require both operands of addition to be the same type and be
bigint
,number
, orstring
.
Extending "plugin:@typescript-eslint/recommended-type-checked"
in an ESLint configuration enables this rule.
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
.
- Flat Config
- Legacy Config
export default tseslint.config({
rules: {
"@typescript-eslint/restrict-plus-operands": "error"
}
});
module.exports = {
"rules": {
"@typescript-eslint/restrict-plus-operands": "error"
}
};
Try this rule in the playground ↗
Examples
- ❌ Incorrect
- ✅ Correct
let foo = 1n + 1;
let fn = (a: string, b: never) => a + b;
Open in Playgroundlet foo = 1n + 1n;
let fn = (a: string, b: string) => a + b;
Open in PlaygroundOptions
This rule accepts the following options, and has more strict settings in the strict and strict-type-checked configs.
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 defaultOptionsRecommended: Options = [
{
allowAny: true,
allowBoolean: true,
allowNullish: true,
allowNumberAndString: true,
allowRegExp: true,
skipCompoundAssignments: false,
},
];
// These options are merged on top of the recommended defaults
const defaultOptionsStrict: Options = [
{
allowAny: false,
allowBoolean: false,
allowNullish: false,
allowNumberAndString: false,
allowRegExp: false,
},
];
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
Whether to allow any
typed values. Default: true
.
Examples of code for this rule with { allowAny: true }
:
- ❌ Incorrect
- ✅ Correct
let fn = (a: number, b: []) => a + b;
let fn = (a: string, b: []) => a + b;
Open in Playgroundlet fn = (a: number, b: any) => a + b;
let fn = (a: string, b: any) => a + b;
Open in PlaygroundallowBoolean
Whether to allow boolean
typed values. Default: true
.
Examples of code for this rule with { allowBoolean: true }
:
- ❌ Incorrect
- ✅ Correct
let fn = (a: number, b: unknown) => a + b;
let fn = (a: string, b: unknown) => a + b;
Open in Playgroundlet fn = (a: number, b: boolean) => a + b;
let fn = (a: string, b: boolean) => a + b;
Open in PlaygroundallowNullish
Whether to allow potentially null
or undefined
typed values. Default: true
.
Examples of code for this rule with { allowNullish: true }
:
- ❌ Incorrect
- ✅ Correct
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 Playgroundlet fn = (a: number, b: undefined) => a + b;
let fn = (a: number, b: null) => a + b;
let fn = (a: string, b: undefined) => a + b;
let fn = (a: string, b: null) => a + b;
Open in PlaygroundallowNumberAndString
Whether to allow bigint
/number
typed values and string
typed values to be added together. Default: true
.
Examples of code for this rule with { allowNumberAndString: true }
:
- ❌ Incorrect
- ✅ Correct
let fn = (a: number, b: unknown) => a + b;
let fn = (a: number, b: never) => a + b;
Open in Playgroundlet fn = (a: number, b: string) => a + b;
let fn = (a: number, b: number | string) => a + b;
Open in PlaygroundallowRegExp
Whether to allow regexp
typed values. Default: true
.
Examples of code for this rule with { allowRegExp: true }
:
- ❌ Incorrect
- ✅ Correct
let fn = (a: number, b: RegExp) => a + b;
Open in Playgroundlet fn = (a: string, b: RegExp) => a + b;
Open in PlaygroundskipCompoundAssignments
Whether to skip compound assignments such as +=
. Default: false
.
Examples of code for this rule with { skipCompoundAssignments: false }
:
- ❌ Incorrect
- ✅ Correct
let foo: bigint = 0n;
foo += 1;
let bar: number[] = [1];
bar += 1;
Open in Playgroundlet foo: bigint = 0n;
foo += 1n;
let bar: number = 1;
bar += 1;
Open in PlaygroundWhen Not To Use It
If you don't mind a risk of "[object Object]"
or incorrect type coercions in your values, then you will not need this rule.
Related To
Further Reading
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.