是否可以检查给定类型是否为并集?
type IsUnion<T> = ???
为什么我需要这样做:在我的代码中,只有某些接收到的类型可以是联合的情况。我使用分布式条件类型来处理它。但是,对于查看此代码的人来说,为什么首先使用DCT并不明显。因此,我希望它是明确的,例如:IsUnion<T> extends true ? T extends Foo ...
我尝试了UnionToIntersection
,但没有结果。我也想出了这个:
type IsUnion<T, U extends T = T> =
T extends any ?
(U extends T ? false : true)
: never
对于非工会,它给出了false
,但是由于某种原因,对于工会,它给出了boolean
……而且我不知道为什么。我也尝试从T infer
到U,但没有成功。
P.S。在某些人看来,我的用例可能并不完美/正确/良好,但是无论如何标题中的问题已经出现,我想知道是否有可能(我认为是可行的,但我自己很难弄清楚)。 / p>
答案 0 :(得分:7)
所以看来我自己想出了一个答案!
这里是类型(感谢Titian Cernicova-Dragomir简化了它!):
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true
type Foo = IsUnion<'abc' | 'def'> // true
type Bar = IsUnion<'abc'> // false
jcalz的UnionToIntersection再派上用场了!
该原理基于并集A | B
不延伸交点A & B
的事实。
UPD。我很傻,没有从问题中发展出我的类型,这也很好:
type IsUnion<T, U extends T = T> =
(T extends any ?
(U extends T ? false : true)
: never) extends false ? false : true
它将联合T
分配给组成要素,也分配给T
,然后检查作为联合的U
是否扩展了组成要素T
。如果是,那么它不是一个联合(但是我仍然不知道为什么不添加extends false ? false : true
也不起作用,即为什么前面的部分为联合返回boolean
)。
答案 1 :(得分:2)
注意::此答案适用于某人明确不想使用
UnionToIntersection
的情况。该版本简单易懂,因此,如果您对U2I
不满,那就去吧。
我只是再次查看了一下,并在@ Gerrit0的帮助下想到了这一点:
// Note: Don't pass U explicitly or this will break. If you want, add a helper
// type to avoid that.
type IsUnion<T, U extends T = T> =
T extends unknown ? [U] extends [T] ? false : true : false;
type Test = IsUnion<1 | 2> // true
type Test2 = IsUnion<1> // false
type Test3 = IsUnion<never> // false
似乎可以进一步简化它,对此我感到非常满意。这里的诀窍是分发T
,而不分发U
,以便您可以进行比较。因此,对于type X = 1 | 2
,您最终要检查[1 | 2] extends [1]
是否为假,因此总体上该类型为true
。如果是T = never
,我们也会解析为false
(感谢Gerrit)。
如果类型不是联合,则T
和U
相同,因此此类型解析为false
。
在某些情况下,这不起作用。由于成员boolean
的分布,具有可分配给另一个成员的成员的任何联合将解析为T
。可能最简单的例子是{}
加入联合时,因为几乎所有东西(甚至是原语)都可以分配给它。您还将看到包含两种对象类型的并集,其中一种是另一种的子类型,即{ x: 1 } | { x: 1, y: 2 }
。
extends
子句(就像Nurbol的回答一样)(...) extends false ? false : true;
never
作为错误的情况:T extends unknown ? [U] extends [T] ? never : true : never;
extends
:true extends IsUnion<T> ? Foo : Bar;
type IfUnion<T, Yes, No> = true extends IsUnion<T> ? Yes : No;
根据您的需要,您可以使用此类型进行很多其他更改。一种想法是对肯定情况使用unknown
。然后,您可以执行T & IsUnion<T>
。或者,您可以仅使用T
并将其命名为AssertUnion
,这样,如果不是联合类型,整个类型就变成never
。天空是极限。
感谢@ Gerrit0和@AnyhowStep在gitter上找到我的错误并提供了解决方法的反馈。