建议
将 NumberConstructor
和 StringConstructor
接口更改为不允许传递类型为 Symbol
的值。目前它接受类型为 any
的值。
尝试调用 Number(Symbol())
、new Number(Symbol())
或 new String(Symbol())
时,所有操作都会在运行时抛出 TypeError
异常。
注意:String(Symbol())
没有问题,只有 new String(Symbol())
会抛出异常。
用例
当将类型为 any
的值传递给 Number
时,存在该值为 symbol
并抛出 TypeError
的风险。
对象键被明确允许为类型 symbol
(如 number | string | symbol
)。将任意对象键传递给 Number
可能也会抛出 TypeError
异常。
示例
检查一个值是否可以强制转换为数字
我刚刚遇到这个问题,当我检查一个对象键是否可以是有效的数组索引时。以下应该是一个错误,因为如果 value
是类型 symbol
,它将抛出异常。
function keyCanBeArrayIndex(value: string | number | symbol): boolean {
return !Number.isNaN(Number(value));
}
让这成为无效将会迫使我编写类似下面的代码:
function canBeArrayIndex(value: string | number | symbol): boolean {
try {
return !Number.isNaN(Number(value));
} catch {
return false;
}
}
检查清单
我的建议满足以下准则:
- 这不会对现有的 TypeScript/JavaScript 代码造成破坏性改变
- 这不会改变现有 JavaScript 代码的运行时行为
- 这可以在不根据表达式的类型发出不同的 JS 的情况下实现
- 这不是一个运行时特性(例如库功能、带有 JavaScript 输出的非 ECMAScript 语法等)
- 这个特性将与 TypeScript's Design Goals 的其他部分保持一致。
9条答案
按热度按时间fwzugrvs1#
这样的代码可以工作,但是它有一个非常无助的错误文本:
au9on6nz2#
你是否经常将
symbol
传递给Number
函数?根据我的经验,这类更改在引起破坏的程度上并不会带来很大的回报。ccrfmcuu3#
@DanielRosenwasser 不多,没有。然而,这种情况确实可能发生。就我个人而言,我在创建一个
Proxy
来 Package 数组时遇到了上述示例。我想捕获set
操作,但只有在键是数字的情况下才这样做。对于今天大多数键来说,函数运行得很好,但在未来几年随着符号的普及,程序可能会开始崩溃。是的,这不是你每天都会遇到的问题,但这就是使用 TypeScript 的好处——它应该在你意识到之前防止你犯这种错误。
此外,当传递一个
symbol
时抛出错误的行为是非常不直观的。当我们执行${Symbol()}
时,TS 报错:首先,这意味着 TS 已经在尝试防止这种情况的发生,其次,它明确表示
String(Symbol())
是完全有效的,这是事实。但是基于这一点,我认为像大多数人一样,我也假设Number(Symbol())
也是有效的,特别是考虑到 任何其他值 时,Number
将产生一个数字或NaN
。pbpqsu0x4#
我认为这里部分问题是,据我所知,TypeScript没有一种方式来表达“除了
symbol
之外的任何类型”的约束。否定类型可以允许这种约束,但我们现在还没有(参见#29317)。根据我的经验,人们确实会使用Number()
构造函数来进行各种运行时转换,因此过度限制其参数到例如number | string
将很可能破坏实际代码。ig9co6j15#
在我的经验中,人们确实会使用
Number()
构造函数进行各种运行时转换。这正是我们应该为这种情况报错的原因——人们正在使用Number()
进行运行时转换,我确信大多数人并不知道传递一个符号会导致错误,从而导致程序崩溃。我完全同意它不应该过于受限。除非有其他东西在传递给
Number
时会抛出错误(如{toString: null, valueOf: null}
在传递给String
时所做的那样),否则所有其他情况都应该是有效的。esbemjvw6#
考虑到 #22251 被合并以防止在模板字符串中使用符号,这显然是有可能的,而且我认为应该以同样的方式处理。所以也许我们允许
String(any)
但不允许String(symbol)
,就像那个修复一样。这种行为将处理我的例子情况,这可能是(如果我没有弄错的话)你可能会遇到的最常见的情况。在这种情况下,也许可以设置一个选项来禁止在模板字符串和
Number
情况下使用any
(也许对于模板字符串已经有了,我不熟悉它)。gv8xihay7#
经过一些探索,我发现尝试调用
new String(Symbol())
(当然这并不是一个好主意,但仍然有可能)也会抛出TypeError
。我已经更新了原始问题以反映这一点,因为它们几乎是完全相同的情况。总之:
TypeScript 接受所有这些而不抱怨。
ozxc1zmp8#
根据标准,任何需要将符号强制转换为字符串的情况(除了特殊情况
String(symbol)
)都会抛出错误。这里可能有很多内容需要覆盖。9avjhtql9#
是的,任何时候一个符号被隐式强制转换为字符串都会抛出错误,这正是应该发生的情况。这种行为已经非常有用,并且按预期工作。
问题在于,现在TS对于一些符号类型转换的情况会抛出错误,但对于其他情况则不会。我们只需要处理这些其他情况即可。