代码之家  ›  专栏  ›  技术社区  ›  Grant Thorshov

Typescript中可以提前返回Typeguard吗?

  •  3
  • Grant Thorshov  · 技术社区  · 2 年前

    我经常遇到这样的情况,在继续之前,我需要在函数中键入check变量。就我个人而言,我喜欢尽可能避免嵌套代码,并经常使用早期返回语句,这样函数的主要功能就在末尾而不是嵌套的。对我来说,它使代码更具可读性和可维护性。然而,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 回复  |  直到 2 年前
        1
  •  3
  •   jcalz    2 年前

    TypeScript control flow analysis 确实支持早期- return 类型防护;问题不在于 回来 ,但是 typeGuardExpr === false check不被视为一种类型保护。

    一般来说,你总是可以颠倒 boolean 通过更改表达式是否具有 logical NOT prefix operator ( ! ) (请注意,您不能只准备 ! ;如果已经有 ! ,则添加一个将不起作用。 !!typeGuardExpr 不会被视为典型的后卫。你应该 去除 这个 ! 如果它已经在那里了。)例如:

    function whatKindOfDessert(dessert: Cupcake | Cookie) {
      if (!(dessert instanceof Cupcake)) return;
      console.log(dessert.cupcakeName) // okay
    }
    

    但是 typeGuardExpr===false 编译器无法分析代码的每一个可能的逻辑含义来缩小范围,因为这样的分析成本太高了。相反,它使用启发式规则,检查特定的编程约定。和 === false 只是不是支持的约定之一。

    当然,这是可以改变的;他们 能够 执行一项检查 typeGuardExpr === true typeGuardExpr===false 传播型防护。但这是在 microsoft/TypeScript#9508 并拒绝了。

    添加这样的额外规则会对编译器性能产生可衡量的负面影响,而这必须通过实际代码行为的切实改进来弥补。如果编程约定不是很常见,那么它可能不值得增加编译时间来支持。这似乎就是microsoft/TypeScript#9508被拒绝的原因(请参阅 this comment )。

    尽管如此,在 microsoft/TypeScript#31105 并被归类为bug。我在 microsoft/TypeScript#53714 等待可能被合并。如果真的发生了这种情况,那么合并后的下一个TypeScript版本将突然支持您的原始代码!目前还不清楚这种情况会不会发生,也不清楚何时发生。

    因此,除非发生这种情况,我的建议是从 typeGuardExpr===false !typeGuardExpr (确保不会以 !!someOtherExpr ,记住)。

    Playground link to code