为什么TypeScript让我添加一个字符串和一个数字?我可以预防吗?

时间:2018-08-30 16:45:33

标签: typescript

以下代码

let k = "1";
k += 1;
console.log(k);

即使在严格模式下,也可以使用TypeScript正确编译。我本来希望tsc失败并出现诸如Cannot add a string and an integer.之类的错误。为什么建立成功?我可以防止这种危险行为吗?

5 个答案:

答案 0 :(得分:4)

“为什么有效,因为它在JS中是有效的”,对于某个操作不是类型错误的原因,这不是一个答案。参见What does "all legal JavaScript is legal TypeScript" mean?

在JavaScript中,像alert("Your position in the queue is " + queuePos)这样的代码是惯用且通用的-通常不是写为"str" + num.toString()的。

TypeScript的立场是,惯用JS不应引起类型错误(在可行时)。这意味着string + number是允许的强制。

然后+=应该做什么的问题是在两个选项之间进行选择:

  • 一致性x = x + y应该与x += y相同
  • 安全性x += ystring操作数之间通常不执行number ,因此应强制执行非法操作

这两种选择都是明智和辩护的; TypeScript恰好选择了第一个。

答案 1 :(得分:2)

恐怕除了建立自己的抽象外,目前无法阻止这种转换。这样的东西(诚然,不是很优雅):

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'.

根据"All legal JavaScript is legal TypeScript",TypeScript的类型检查的通常策略是防止出现明显错误且实际上没有用的情况。例如,防止将字符串传递到Math.max。但是,与本示例不同,尽管并不总是希望在字符串和数字之间使用+运算符,但它确实是有效的操作,并且在实践中经常使用,以致于编译器无法使用。由于x += y等效于x = x + y,并且在x是字符串时总是产生一个字符串,因此赋值本身也是有效的。这是编译器最有可能保持正常状态的情况之一。问题#20131的目的是使其他一些操作发出警告,但特别是不包括此警告。

您可能已经了解到,成功地防止了相反的情况,因为预计变量不会使用添加分配运算符更改其类型。

let y = 1;
y += "1"; // Type 'string' is not assignable to type 'number'

另请参阅:

答案 2 :(得分:0)

简而言之:因为@Explosion Pills已经指出,它是有效的JS和Typescript。

原因是k += 1只是k = k + 1的语法糖,人们期望它是 11 。 所以类似的事情也可以:

let text = "hello ";
text += "world!"
console.log(text); 

最终成为你好世界!

答案 3 :(得分:0)

您可以使用tslint规则restrict-plus-operands来预防此类事故:

  

添加两个变量时,操作数必须均为数字类型或字符串类型。

     

配置示例:

     

WHERE MATCH(dbase-field) AGAINST('$querystring' IN NATURAL LANGUAGE MODE) AND if (there is any text in dbase-field2) { MATCH(dbase-field2) AGAINST('$querystring' IN NATURAL LANGUAGE MODE) }

如果启用该规则,则以下代码:

"restrict-plus-operands": true

将导致:

  

错误:.ts-'+'操作的操作数必须是两个字符串或两个数字,但找到5 +“ foo”。考虑使用模板文字。

该规则不仅禁止在字符串和数字之间使用const x = 5; const y = 'foo'; const z = x + y; console.log(z); ,而且还禁止在左侧类型与右侧类型不同时使用+

答案 4 :(得分:0)

TSLint建议使用模板文字而不是强制使用字符串和数字变量, 例如:'Hello ' + person.name将变成`Hello ${person.name}`