提问人:Grant Thorshov 提问时间:8/7/2023 最后编辑:Grant Thorshov 更新时间:8/7/2023 访问量:135
Typescript 中是否可以提前返回 Typeguard?
Are Early-Return Typeguards Possible in Typescript?
问:
我经常遇到这样的情况,我需要在继续之前在函数中输入检查变量。就我个人而言,我喜欢尽可能避免嵌套代码,并经常使用 early-return 语句,以便函数的主要功能位于末尾且未嵌套。对我来说,它使代码更具可读性和可维护性。但是,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)
答:
TypeScript 的控制流分析确实支持早期类型的防护;问题不在于 ,而在于检查不被视为类型保护。return
return
typeGuardExpr === false
一般来说,你总是可以通过改变表达式是否具有逻辑 NOT 前缀运算符 (!)
来反转类型保护表达式的意义(请注意,你不能只在前面加上一个;如果已经有一个 ,那么添加一个是行不通的。 不会被视为类型后卫。如果它已经存在,则应将其删除。对于您的示例,如下所示:boolean
!
!
!!typeGuardExpr
!
function whatKindOfDessert(dessert: Cupcake | Cookie) {
if (!(dessert instanceof Cupcake)) return;
console.log(dessert.cupcakeName) // okay
}
但不能以这种方式工作,仅仅是因为没有人实现它。编译器无法分析代码中所有可能的逻辑含义以缩小范围,因为这种分析的成本高得令人望而却步。相反,它使用启发式规则,检查特定的编程约定。只是不是受支持的约定之一。typeGuardExpr === false
=== false
当然,这是可以改变的;他们可以实现一个检查,使类型保护并传播。但这是在 microsoft/TypeScript#9508 中建议的,但被拒绝了。typeGuardExpr === true
typeGuardExpr === false
添加这样的额外规则会对编译器性能产生可衡量的负面影响,而这必须通过对实际代码行为的切实改进来支付。如果编程约定不是很常见,则可能认为不值得增加编译时间来支持。这似乎就是 microsoft/TypeScript#9508 被拒绝的原因(请参阅此评论)。
尽管如此,该问题还是在 microsoft/TypeScript#31105 上再次提出,并被归类为错误。我在 microsoft/TypeScript#53714 上看到一个拉取请求,等待可能合并。如果确实发生了这种情况,那么合并后的下一个 TypeScript 版本将突然支持您的原始代码!不过,目前尚不清楚这是否会发生,也不清楚何时发生。
因此,除非发生这种情况,否则我的建议是从切换到(确保不要以 ,记住)。typeGuardExpr === false
!typeGuardExpr
!!someOtherExpr
评论
!(dessert instanceof Cupcake)
dessert instanceof Cupcake === false
(otherTypeGuard) === false