有没有一种方法可以防止TypeScript中的联合类型? [英] Is there a way to prevent union types in TypeScript?

查看:66
本文介绍了有没有一种方法可以防止TypeScript中的联合类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

B类型仍然是联合.有人可以教育我吗?

这是解决方案

我不确定用例是什么,但是如果传递的类型是联合类型,我们可以强制将NoUnion更改为never.

正如其他提到的条件类型通过联合分布一样,这称为

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|false,因此NoUnion<boolean>实际上将是never.如果没有更多关于您要实现的目标的详细信息,很难知道这是否会破坏交易,但是可以通过将boolean作为特例来解决:

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

注意:UnionToIntersection来自此处

I'm new to conditional types, so I tried the most obvious static way, no success:

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

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

The B type is still a union. Would somebody please school me?

Here's a playground.

解决方案

I am unsure what the usecase for this is, but we can force the NoUnion to never if the passed type is a union type.

As other mentioned conditional types distribute over a union, this is called distributive conditional types

Conditional types in which the checked type is a naked type parameter are called distributive conditional types. Distributive conditional types are automatically distributed over union types during instantiation. For example, an instantiation of T extends U ? X : Y with the type argument A | B | C for T is resolved as (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y).

The key there is 'naked type', if we wrap the type in a tuple type for example the conditional type will no longer be distributive.

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

The last example is an issue, since boolean is seen by the compiler as true|false, NoUnion<boolean> will actually be never. Without more details of what exactly you are trying to achieve it is difficult to know if this is a deal breaker, but it could be solved by treating boolean as a special case:

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

Note: UnionToIntersection is taken from here

这篇关于有没有一种方法可以防止TypeScript中的联合类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆