🔎 搜索词
"typeguard", "is operator"
🕗 版本与回归信息
在typescript@5.1.3及更高版本中进行测试
⏯ 代码沙盒链接
- 无响应*
💻 实际行为
TypeScript无法推断出'this'的类型为'Test<Exclude<kind, kind.c>>',尽管存在类型保护。在'do'方法中,TypeScript抛出一个TSError,指出'this.value':对象可能是'undefined'。
如果我们明确将'this'转换为'Test<Exclude<kind, kind.c>>',我们可以访问'value'属性,它按预期工作。然而,不知何故,类型保护没有产生相同的效果。
🙂 预期行为
由于在'this.value.id'行周围存在类型保护,TypeScript应该将'this'处理为'Test<Exclude<kind, kind.c>>'类型。至少,这是我对类型保护的理解。
关于问题的附加信息
- 无响应*
4条答案
按热度按时间xmjla07d1#
在这里我们无法做太多事情——即使在类型保护之后,
value
的类型仍然通用,并且急切地解析一个基于类型参数的条件的类型是不安全的。这是错误的;你观察到的错误与下面的错误相同然而,在寻找解决方法时,我发现了另一个错误
u5rb5r592#
问题在于,这种缩小范围的方法没有返回类型注解(我们也可以通过注解返回类型来"修复"这个问题) - 因此它必须推断返回类型。
为了做到这一点,它开始计算
Test<kind>.doSomething
的返回类型,进入控制流逻辑,并最终根据以下内容选择缩小的类型:出于某种原因,当它出错时,第一个检查返回
true
,从而选择了t
- 而当它没有出错时,是第二个检查返回了true
。实际上,对于那些在“损坏”的情况下的所有类型,所有这些检查都返回了true
。通过进一步检查,我们可以了解到它没有返回
true
,因为它对结果很有信心。实际上的结果是1
(也称为Ternary.Unknown
)。我们永远不会知道这个,因为那被“转换”为boolean
- 但无论如何,如果双向检查都返回Ternany.Unknown
,我们如何确定在这里应该选择哪一个?另一方面,如果整个事情都返回neverType
,那么紧跟其后的代码可能会创建这两种类型的交集,这可能有助于解决这个问题:TS Playgroundknsnq2tg3#
一个稍微小一点但更容易理解的这个bug(或其他bug)的例子:
我正在努力弄清楚该怎么做。有什么建议吗?
8fq7wneg4#
这是一个不同的问题 - 它不使用任何用户定义的类型保护。
TypeScript 今天还无法进行这种推理。通过检查
typeof args.foo === "number"
,你可以确保编译器args.foo
具有T & number
类型,但这并不会“传播”到父类型(args
的类型)。我现在称之为设计限制。