有没有办法阻止TypeScript中的联合类型?

时间:2018-06-01 08:47:58

标签: typescript functional-programming

我是条件类型的新手,所以我尝试了最明显的静态方法,但没有成功:

type NoUnion<Key> =
  Key extends 'a' ? 'a' :
  Key extends 'b' ? 'b' :
  never;

type B = NoUnion<'a'|'b'>;

B型仍然是一个联盟。有人请你上学吗?

这里是playground

3 个答案:

答案 0 :(得分:7)

我不确定这是什么用例,但如果传递的类型是联合类型,我们可以强制NoUnionnever

正如其他提到的条件类型在union上分布一样,这称为distributive conditional types

  

检查类型是裸类型参数的条件类型称为分布式条件类型。分布式条件类型在实例化期间自动分布在联合类型上。例如,T的实例化扩展了U? X:Y,类型参数为A | B | T的C被解析为(A扩展U?X:Y)| (B扩展U?X:Y)| (C扩展U?X:Y)。

如果我们将类型包装在元组类型中,那么键是“裸类型”,例如条件类型将不再是分布式的。

type UnionToIntersection<U> = 
    (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never 

type NoUnion<Key> =
    // If this is a simple type UnionToIntersection<Key> will be the same type, otherwise it will an intersection of all types in the union and probably will not extend `Key`
    [Key] extends [UnionToIntersection<Key>] ? Key : never; 

type A = NoUnion<'a'|'b'>; // never
type B = NoUnion<'a'>; // a
type OtherUnion = NoUnion<string | number>; // never
type OtherType = NoUnion<number>; // number
type OtherBoolean = NoUnion<boolean>; // never since boolean is just true|false

最后一个示例是一个问题,因为编译器将boolean视为true|falseNoUnion<boolean>实际上是never。如果没有更多关于你究竟想要实现的细节,很难知道这是否是一个交易破坏者,但可以通过将boolean视为一个特例来解决:

type NoUnion<Key> =
    [Key] extends [boolean] ? boolean :
    [Key] extends [UnionToIntersection<Key>] ? Key : never;

注意:UnionToIntersection取自here

答案 1 :(得分:3)

顺便说一下,&#34;更简单&#34;一个我试图想出来的样子:

type NotAUnion<T> = [T] extends [infer U] ? 
  U extends any ? [T] extends [U] ? T : never : never : never;

这应该有用(请测试一下;不确定为什么我在my answer to another question错误的原始版本,但它现在已修复)。它与UnionToIntersection的想法类似:您希望确保T类型T可分配给T的每个部分。一般来说,只有当@Url.Action("ArticleDetails", "Information", new { slug = article.Slug }) 是一个只有一个组成部分的联盟时(这也称为&#34;不是联盟&#34;),这是唯一的。

无论如何,@ TitianCernicovaDragomir的答案也完全没问题。只是想在那里得到这个版本。欢呼声。

答案 2 :(得分:1)

这也有效:

type NoUnion<T, U = T> = T extends U ? [U] extends [T] ? T : never : never;