打字稿将联合转换为交集[重复]

Posted

技术标签:

【中文标题】打字稿将联合转换为交集[重复]【英文标题】:Typescript Convert Union to intersection [duplicate] 【发布时间】:2019-07-23 02:28:47 【问题描述】:
enum keyEnum 
    firstKey = 1,
    secKey = 2,
    thirdKey = 3
;

enum firstPropEnum 
    a = 'a',
    b = 'b',
;

enum secPropEnum 
    c = 'c',
    d = 'd',
;

type firstAndSecPropEnum = firstPropEnum | secPropEnum;

type keyPropObj = 
    [keyEnum.firstKey]:  prop: firstPropEnum ,
    [keyEnum.secKey]:  prop: secPropEnum ,
    [keyEnum.thirdKey]:  prop: firstAndSecPropEnum ,
;

type getKeyProp<T extends keyEnum> = keyPropObj[T]['prop'];

type getKeyPropResult1 = getKeyProp<keyEnum.thirdKey | keyEnum.secKey> // Result secPropEnum | firstPropEnum
// Expected Result secPropEnum.
type getKeyPropResult2 = getKeyProp<keyEnum.thirdKey | keyEnum.firstKey> // Result firstPropEnum | secPropEnum
// Expected Result firstPropEnum.
type getKeyPropResult3 = getKeyProp<keyEnum.secKey | keyEnum.firstKey> // Result firstPropEnum | secPropEnum
// Expected Result never;

所以我期待得到一个交叉点而不是一个联合。 Result 应该是一个在所有结果 props 中通用的值。 任何对此的帮助将不胜感激。

【问题讨论】:

【参考方案1】:

您 can convert unions to intersections 使用 TS2.8 及更高版本。在你的情况下,我可能会做这样的事情:

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

// use Lookup<T, K> instead of T[K] in cases where the compiler 
//  cannot verify that K is a key of T
type Lookup<T, K> = K extends keyof T ? T[K] : never;

type getKeyProp<T extends keyEnum> = Lookup<UnionToIntersection<keyPropObj[T]>, 'prop'>;

你想要的类型会根据需要掉出来:

type getKeyPropResult1 = getKeyProp<keyEnum.thirdKey | keyEnum.secKey> // secPropEnum.
type getKeyPropResult2 = getKeyProp<keyEnum.thirdKey | keyEnum.firstKey> // firstPropEnum.
type getKeyPropResult3 = getKeyProp<keyEnum.secKey | keyEnum.firstKey> // never.

希望对您有所帮助。祝你好运!

【讨论】:

我们也可以Lookup&lt;T, K extends keyof T&gt; = T[K] 以获得更好的智能感知吗?【参考方案2】:

嗯,你总是可以自己相交类型:

type getKeyPropResult1 = getKeyProp<keyEnum.thirdKey> & getKeyProp<keyEnum.secKey>
type getKeyPropResult2 = getKeyProp<keyEnum.thirdKey> & getKeyProp<keyEnum.firstKey>
type getKeyPropResult3 = getKeyProp<keyEnum.secKey> & getKeyProp<keyEnum.firstKey>

一个相当丑陋的替代方案,最多可用于 6 个键:

type getKeyPropSingle<T extends keyEnum> = keyPropObj[T]['prop'];
type getKeyProp<
    T1 extends keyEnum | null = null,
    T2 extends keyEnum | null = null,
    T3 extends keyEnum | null = null,
    T4 extends keyEnum | null = null,
    T5 extends keyEnum | null = null,
    T6 extends keyEnum | null = null,
> = (T1 extends keyEnum ? getKeyPropSingle<T1> : unknown) &
    (T2 extends keyEnum ? getKeyPropSingle<T2> : unknown) &
    (T3 extends keyEnum ? getKeyPropSingle<T3> : unknown) &
    (T4 extends keyEnum ? getKeyPropSingle<T4> : unknown) &
    (T5 extends keyEnum ? getKeyPropSingle<T5> : unknown) &
    (T6 extends keyEnum ? getKeyPropSingle<T6> : unknown);

type second = getKeyProp<keyEnum.secKey>;
type getKeyPropResult1 = getKeyProp<keyEnum.thirdKey, keyEnum.secKey>
type getKeyPropResult2 = getKeyProp<keyEnum.thirdKey, keyEnum.firstKey>
type getKeyPropResult3 = getKeyProp<keyEnum.secKey, keyEnum.firstKey>

【讨论】:

我一直在寻找一种更具可扩展性的方法。有没有办法遍历枚举并相应地进行。 @AmolGupta:可能没有干净的解决方案,至少我不知道。添加了另一个在某种程度上适用于 lack of variadic generics 的选项。 @AmolGupta:有趣的是,这实际上是可能的,但老实说,我既不会编写这样的代码,也不推荐使用它。条件类型与映射类型的组合难以阅读和理解。

以上是关于打字稿将联合转换为交集[重复]的主要内容,如果未能解决你的问题,请参考以下文章

将联合类型转换为交集类型[重复]

使用Angular或打字稿将字符串的第一个字母大写[重复]

将打字稿接口属性类型转换为联合[重复]

打字稿将数组转换为 JSON

函数的打字稿联合/交集类型

我可以使用打字稿将对象键限制为枚举值吗?