在算术中,以下内容是正确的:设'a'是任何正实数,因此:
-a = a*(-1)
Typescript 编译器似乎没有以类型安全的方式重现算术规则。看:
(一(按预期工作
以下行生成此错误消息:">算术运算的左侧必须是类型'any'、'number'、'big-int'或枚举类型">
const f = (a: string) => a*(-1) // error
const g = (a: {}) => a*(-1) // error
(二(工作不按预期
在下面的场景中,所有算术计算都使用非数值类型不安全地执行,并且不会引发编译时错误。
const f = (a: string) => -a
const g = (a: {}) => -a
console.log(f('hi there')) // produces 'NaN' !
console.log(g('hi there')) // produces 'NaN'
console.log(g(2)) // produces -2
问题
- 为什么 TS 在一元运算符中不如在二进制运算符中安全?
注意:TS 版本 3.7.2/类型"未知"按预期工作
ECMAScript 规范指出,一元+
和一元-
运算符都对其输入表达式执行抽象操作ToNumber()
:
12.5.6 一元 + 运算符
注意 一元 + 运算符将其操作数转换为数字类型*。
12.5.6.1 运行时语义:评估
一元表达式 : + 一元表达式
让 expr 是计算 UnaryExpression 的结果。
返回?ToNumber(?GetValue(expr((。
12.5.7 一元 - 运算符
注意 一元运算符将其操作数转换为数字类型*,然后对其进行求反。否定 +0 产生 -0,否定 -0 产生 +0。
12.5.7.1 运行时语义:评估
一元表达式 : - 一元表达式
让 expr 是计算 UnaryExpression 的结果。
让旧值是 ?ToNumber(?GetValue(expr((。
如果 oldValue 为 NaN,则返回 NaN。
返回否定 oldValue 的结果;即计算一个大小相同但符号相反的数字。
*强调添加
TypeScript 没有理由对接受的类型施加任意限制,因为根据规范,主要预期用途是执行类型转换。
回应伊曼纽尔·温蒂勒对上述问题的评论:
二元运算符还执行类型转换
规范不使用相同的语言,即
[...] 将其操作数转换为数字类型
在 乘法表达式 下;也就是说,虽然乘法*
、/
%
运算符确实执行类型转换,但它不是它们的主要预期用法。