以下代码
let k = "1";
k += 1;
console.log(k);
使用 TypeScript 正确编译,即使在严格模式下也是如此。我本来希望 tsc 会失败并出现一些错误,例如Cannot add a string and an integer.
.为什么它能成功构建?我可以防止这种危险行为吗?
"它是有效的,因为它在JS中是有效的"在为什么某个操作不是类型错误的上下文中是一个非答案;请参阅"所有合法的JavaScript都是合法的TypeScript"是什么意思?
在 JavaScript 中,像alert("Your position in the queue is " + queuePos)
这样的代码是惯用的和常见的——它通常不写成"str" + num.toString()
。
TypeScript 的立场是惯用的 JS 不应该导致类型错误(如果可行(。这意味着string + number
是允许的胁迫。
+=
应该做什么的问题就是在两个选项之间进行选择:
-
一致性:
x = x + y
应与x += y
相同 -
安全性:
x += y
通常不是在string
和number
操作者之间进行的,因此应该是非法胁迫
这两种选择都是明智和可辩护的;TypeScript 碰巧选择了第一个。
您可以使用 TypeScript-ESLint 规则限制加操作数来防止此类事故:
添加两个变量时,操作数必须都是 number 或字符串类型。
配置示例:
"restrict-plus-operands": true
如果启用该规则,则以下代码:
const x = 5;
const y = 'foo';
const z = x + y;
console.log(z);
将导致:
错误:.ts - "+"操作的操作数必须是两个字符串或两个数字,但找到 5 + "foo"。请考虑使用模板文本。
该规则不仅防止在字符串和数字之间使用+
,而且还防止在左侧类型与右侧类型不同时使用+=
。
恐怕除了构建自己的抽象之外,目前没有办法阻止这种转换。像这样的东西(诚然,不是很优雅(:
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'.
根据"所有合法的JavaScript都是合法的TypeScript",TypeScript的类型检查的通常策略是防止明显错误且从未真正有用的情况。例如,阻止将字符串传递给Math.max
。然而,与此示例不同的是,字符串和数字之间的+
运算符尽管并不总是可取的,但确实是一个有效的操作,并且在实践中使用得太频繁,以至于编译器禁止使用。由于x += y
等价于x = x + y
,并且当x
是字符串时总是产生字符串,因此赋值本身也是有效的。这是编译器最有可能保持正常的情况之一。问题 #20131 旨在使更多操作引发警告,但不包括此操作。
您可能已经了解,可以成功防止相反的情况,因为变量不会使用 add-assignment 运算符更改其类型。
let y = 1;
y += "1"; // Type 'string' is not assignable to type 'number'
另请参阅:
- "所有合法的JavaScript都是合法的TypeScript"是什么意思?
- 隐式类型转换时出现 TypeScript 错误
简而言之:因为它是有效的JS和Typescript@Explosion正如Pills已经指出的那样。
原因是k += 1
只是k = k + 1
的句法糖,人们期望是11。 所以这样的东西也有效:
let text = "hello ";
text += "world!"
console.log(text);
最终成为你好世界!
TSLint 建议使用模板文字而不是字符串和数字变量的强制, 例如:'Hello ' + person.name
会变得`Hello ${person.name}`