【问题标题】:Infer union types of type guards in TypeScript在 TypeScript 中推断类型保护的联合类型
【发布时间】:2019-02-13 16:07:57
【问题描述】:

TypeScript 似乎无法推断类型保护的联合类型。例如,考虑一个将类型保护数组与以下签名组合的函数

function combine<T>(guards: ((x: any) => x is T)[]): (x: any) => x is T

并考虑以下具有不同属性的 AB 类型保护

function isA(x: any): x is A
function isB(x: any): x is B

现在我希望combine([isA, isB]) 能够工作并具有推断类型(x: any) =&gt; x is A | B,但是我收到一个错误消息,指出((x: any) =&gt; x is A | (x: any) =&gt; x is B)[] 类型的参数不能分配给(x: any) =&gt; x is A 类型的参数,这意味着@987654329 @ 被推断为A 而不是A | B

当明确指定T 时,即combine&lt;A|B&gt;([isA, isB]),它按预期工作。有没有办法更改combine 的签名以便可以推断出这一点?

【问题讨论】:

  • 你总是可以使用function combine2&lt;T, U&gt;(guards: [((x: any) =&gt; x is T), ((x: any) =&gt; x is U)]): (x: any) =&gt; x is T | U,但我猜你想接受一个包含不同数量项目的数组?
  • 没错,我正在寻找一种适用于任何(正数)数组元素的解决方案。

标签: typescript


【解决方案1】:

您可以使用类型参数来表示整个函数,而不仅仅是受保护的类型。这允许编译器推断保护函数的联合。然后我们可以使用条件类型来提取受保护类型的联合:

type GuardType<T> = T extends (o: any) => o is infer U ? U : never

class A { q: any }
class B { p: any }
declare function isA(x: any): x is A
declare function isB(x: any): x is B

declare function combine<T extends ((x: any) => x is any)>(guards: T[]): (x: any) => x is GuardType<T>

let isAB = combine([isA, isB]); // (x:any) => x is A|B

【讨论】:

  • 我一直在努力解决这个问题,你刚刚救了我 stackoverflow.com/questions/52236191/… 我已经提交了一个答案,但它相当hacky,我想知道是否有更好的解决方案。
  • @ClémentPrévost 我看到了你的回答,我是赞成它的人:)
  • 这太棒了。我想知道如何使用交叉类型来做到这一点,以实现这一点:let isAB = combine([isA, isB]); // (x:any) =&gt; x is A &amp; B
  • @blid 我想你也可以这样做,UnionToIntersection 是你唯一需要的额外东西stackoverflow.com/questions/50374908/…
  • @TitianCernicova-Dragomir 谢谢你,它就像一个魅力:stackblitz.com/edit/typescript-k4wvjb
猜你喜欢
  • 1970-01-01
  • 2018-07-26
  • 2021-06-05
  • 2021-12-21
  • 2020-01-14
  • 2019-09-17
  • 1970-01-01
  • 2018-12-03
  • 2018-07-03
相关资源
最近更新 更多