The following code
let k = "1";
k += 1;
console.log(k);
compiles correctly using TypeScript, even in strict mode. I would have expected tsc to fail with some error like Cannot add a string and an integer.
. Why does it build successfuly? Can I prevent this dangerous behavior?
"It's valid because it's valid in JS" is a non-answer in the context of why a certain operation isn't a type error; see What does "all legal JavaScript is legal TypeScript" mean?
In JavaScript, code like alert("Your position in the queue is " + queuePos)
is idiomatic and common -- it is not commonly written as "str" + num.toString()
.
TypeScript's position is that idiomatic JS should not cause type errors (when practical). This means that string + number
is an allowed coercion.
The question of what +=
should do is then a matter of choosing between two options:
x = x + y
should be identical to x += y
x += y
is not commonly done between string
and number
operands, so should be an illegal coercionBoth choices are sensible and defensible; TypeScript happened to choose the first.
You can prevent this sort of accident with the TypeScript-ESLint rule restrict-plus-operands:
When adding two variables, operands must both be of type number or of type string.
Config examples:
"restrict-plus-operands": true
If you enable that rule, the following code:
const x = 5;
const y = 'foo';
const z = x + y;
console.log(z);
will result in:
ERROR: .ts - Operands of '+' operation must either be both strings or both numbers, but found 5 + "foo". Consider using template literals.
The rule not only prevents use of +
between strings and numbers, but it also prevents use of +=
when the left-hand side type is different from the right-hand side type.
I'm afraid that there is currently no way of preventing such a conversion, aside from building an abstraction of your own. Something like this (admittedly, not very elegant):
function safe_add(x: string, y: string): string { return x + y; }
let x = "1";
x = safe_add(z, 1); // Argument of type '1' is not assignable to parameter of type 'string'.
The usual policy of TypeScript's type checking, according to "All legal JavaScript is legal TypeScript", is to prevent situations which are clearly wrong and never actually useful. For example, passing a string to Math.max
is prevented. Unlike this example however, the +
operator between a string and a number, despite not always desirable, is indeed a valid operation, and is employed too often in practice to be barred by the compiler. As x += y
is equivalent to x = x + y
, and always resulting in a string when x
is a string, the assignment itself is also valid. This is one of those cases that are most likely going to remain as OK by the compiler. Issue #20131 aims to make a few more operations throw a warning, but this one in particular is not included.
As you might already understand, the opposite is successfully prevented, since a variable is not expected to change its type with the add-assignment operator.
let y = 1;
y += "1"; // Type 'string' is not assignable to type 'number'
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With