我经常遇到这样的情况,在继续之前,我需要对函数中的变量进行类型检查。就我个人而言,我喜欢尽可能避免嵌套代码,并经常使用早期返回语句,以便函数的主要功能在最后并且不嵌套。对我来说,它使代码更具可读性和可维护性。但是,Typescript类型检查器似乎不喜欢这样。
下面的代码让类型检查器很生气,因为cupcake_name
可能不是dessert
变量的属性。
function what_kind_of_cupcake(dessert: Cupcake | Cookie){
if (dessert instanceof Cupcake === false) return
console.log(dessert.cupcake_name)
}
字符串
但是,这段代码满足Typescript。
function what_kind_of_cupcake(dessert: Cupcake | Cookie){
if (dessert instanceof Cupcake) {
console.log(dessert.cupcake_name)
}
}
型
我知道这两种功能在技术上都可以工作,并且这两种编码风格都有时间和地点。这也是我面临的问题的一个非常简化的版本。我的问题是关于类型检查器如何理解这两个函数,以及是否有一种方法可以修改TSconfig以允许以前的编码风格。
为了解决这个问题,我有时会重新声明变量,并使用as
关键字来绕过类型检查器,尽管我宁愿不必一直这样做。
function what_kind_of_cupcake(dessert: Cupcake | Cookie){
// type of 'desert' is undetermined at this point. Could be a Cupcake or a Cookie
if (dessert instanceof Cupcake === false) return
// recast dessert?
dessert = dessert as Cupcake
console.log(dessert.cupcake_name)
型
1条答案
按热度按时间kxkpmulp1#
TypeScript的控制流分析确实支持早期的
return
类型保护;问题不在于return
,而在于typeGuardExpr === false
检查没有被视为类型保护。一般来说,你可以通过改变
boolean
类型的保护表达式是否有logical NOT prefix operator (!
)来反转它的含义(注意,你不能只是在前面加上!
;如果已经有一个!
,那么添加一个将不起作用。!!typeGuardExpr
不会被视为类型保护。如果!
已经存在,则应该 * 删除 * 它。)对于您的示例,它看起来像:字符串
但是
typeGuardExpr === false
不能以这种方式工作,原因很简单,因为没有人实现它。编译器不能分析代码的每一个可能的逻辑含义来缩小范围,因为这样的分析代价太高。相反,它使用启发式规则,检查特定的编程约定。而=== false
并不是受支持的约定之一。当然,这是可以改变的;他们可以实现一个检查,使
typeGuardExpr === true
和typeGuardExpr === false
传播类型保护。但这在microsoft/TypeScript#9508中被建议并被拒绝。添加这样的额外规则对编译器性能有可衡量的负面影响,这将不得不通过实际代码行为的切实改进来补偿。如果一个编程约定不是很常见,那么可能不值得增加编译时间来支持它。这似乎就是为什么microsoft/TypeScript#9508被拒绝的原因(请参阅此评论)。
尽管如此,这个问题在microsoft/TypeScript#31105上再次被提出,并被归类为bug。我在microsoft/TypeScript#53714上看到一个pull请求,可能正在等待合并。如果确实发生了这种情况,那么合并后的下一个TypeScript版本将突然支持您的原始代码!不过,目前还不清楚这是否会发生,也不清楚何时会发生。
因此,除非发生这种情况,否则我的建议是从
typeGuardExpr === false
切换到!typeGuardExpr
(记住,确保不要以!!someOtherExpr
结束)。Playground链接到代码