我经常遇到这样的情况,在继续之前,我需要在函数中键入check一个变量.就我个人而言,我喜欢在可能的情况下避免嵌套代码,并经常使用早期返回语句,以便函数的主要功能位于末尾并且不嵌套.对我来说,它使代码更具可读性和可维护性.然而,打字文本类型判断器似乎不喜欢这样.

下面的代码让类型判断器很生气,因为cupcake_name可能不是dessert变量的属性.

function what_kind_of_cupcake(dessert: Cupcake | Cookie){

    if (dessert instanceof Cupcake === false) return 

    console.log(dessert.cupcake_name)

}

但是,此代码满足打字脚本的要求.

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)

推荐答案

TypeScrip的control flow analysis确实支持早期的return类型保护;问题不在return,而是typeGuardExpr === false判断不被视为类型保护.

一般来说,您总是可以通过更改表达式是否有logical NOT prefix operator (!)来颠倒boolean类型保护表达式的含义(请注意,您不能只在前面加上!;如果已经有!,则加1将不起作用.!!typeGuardExpr不会被视为典型的后卫.如果!已经在那里,则应该是remove.)对于您的示例,如下所示:

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

typeGuardExpr === false不是这样运作的,原因很简单,因为没有人实施它.编译器不能分析代码的每一个可能的逻辑含义来缩小范围,因为这样的分析成本高得令人望而却步.相反,它使用启发式规则,判断特定的编程约定.=== false不是受支持的约定之一.

当然,这是可以改变的;它们could实现了使typeGuardExpr === truetypeGuardExpr === false传播类型警卫的判断.但这是在microsoft/TypeScript#9508年提出的,但被拒绝了.

添加这样的额外规则对编译器性能有可测量的负面影响,而这必须通过实际代码行为的切实改进来弥补.如果编程约定不是很常见,那么可能不值得增加编译时间来支持它.这似乎就是微软/TypeScrip#9508被拒绝的原因.

尽管如此,这个问题在microsoft/TypeScript#31105分再次被建议,并被归类为错误.我在microsoft/TypeScript#53714处看到一个等待合并的拉取请求.如果确实发生了这种情况,那么合并后的下一个版本的TypeScrip将突然支持您的原始代码!不过,目前还不清楚这是否会发生,或者何时发生.

因此,除非发生这种情况,否则我的建议是从typeGuardExpr === false切换到!typeGuardExpr(请记住,不要以!!someOtherExpr结尾).

Playground link to code

Typescript相关问答推荐

TypScript中的算法运算式

类型脚本接口索引签名

将props传递给子组件并有条件地呈现它''

如何表示多层深度的泛型类型数组?

TypeScrip原始字符串没有方法

打字类型保护递归判断

为什么不能使用$EVENT接收字符串数组?

分解对象时出现打字错误

ApexCharts条形图未显示最小值.负值

如何在NX工作区项目.json中设置类似angular.json的两个项目构建配置?

判断映射类型内的键值的条件类型

在组件卸载时try 使用useEffect清除状态时发生冲突.react +打字

声明遵循映射类型的接口

如何正确地将元组表格输入到对象数组实用函数(如ZIP)中,避免在TypeScrip 5.2.2中合并所有值

字幕子集一个元组的多个元素

如何键入对象转换器

仅当类型为联合类型时映射属性类型

断言同级为true或抛出错误的Typescript函数

类型string不可分配给类型string| 联盟| 的'

有没有办法将类型与关键更改相匹配?