Typescript 如何将并集类型转换为元组类型

Typescript 如何将并集类型转换为元组类型,typescript,Typescript,例如,我有一个类型 type abc = 'a' | 'b' | 'c'; 如何使元组类型在编译时包含union的所有元素 type t = ['a','b', 'c']; 很容易从元组类型转换为联合类型;例如,请参见。但恰恰相反,从一个并集到一个元组的转换是一个非常糟糕的想法,你不应该尝试去做。让我们先做,然后自责: // oh boy don't do this type UnionToIntersection<U> = (U extends any ? (k: U) =

例如,我有一个类型

type abc = 'a' | 'b' | 'c';
如何使元组类型在编译时包含union的所有元素

type t = ['a','b', 'c'];

很容易从元组类型转换为联合类型;例如,请参见。但恰恰相反,从一个并集到一个元组的转换是一个非常糟糕的想法,你不应该尝试去做。让我们先做,然后自责:

// oh boy don't do this
type UnionToIntersection<U> =
  (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
type LastOf<T> =
  UnionToIntersection<T extends any ? () => T : never> extends () => (infer R) ? R : never

// TS4.0+
type Push<T extends any[], V> = [...T, V];

// TS4.1+
type TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> =
  true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>

type abc = 'a' | 'b' | 'c';
type t = TuplifyUnion<abc>; // ["a", "b", "c"] 
//噢,孩子,别这样
类型UnionToIntersection=
(U扩展任何?(k:U)=>void:never)扩展((k:inferi)=>void)?I:从来没有
类型=
UnionToIntersection T:never>extends()=>(推断R)?R:从来没有
//TS4.0+
类型Push=[…T,V];
//TS4.1+
类型TuplifyUnion=
真的吗?[]:推送
abc类型='a'|'b'|'c';
类型t=TuplifyUnion

这种方法很有效,但我真的建议不要将其用于任何官方用途或任何生产代码中。原因如下:

  • 不能依赖于联合类型的排序。这是编译器的一个实现细节;由于
    X | Y
    相当于
    Y | X
    ,因此编译器可以随意更改其中一个。有时它确实:

      type TypeTrue1A = TuplifyUnion<true | 1 | "a">; // [true, 1, "a"] I've sometimes faced a situation in which I want to derive type B from type A but find that either TS does not support it, or that doing the transformation results in code that's hard to follow. Sometimes, the choice of deriving B from A is arbitrary and I could just as well derive in the other direction. Here if you can start with your tuple, you can easily derive a type that covers all the values that the tuple accepts as elements:

    type X = ["a", "b", "c"];
    
    type AnyElementOf<T extends any[]> = T[number];
    
    type AnyElementOfX = AnyElementOf<X>;
    

    类型TypeTrue1A=TuplifyUnion;//[true,1,“a”]很容易从元组类型转换为联合类型;例如,请参见。但恰恰相反,从一个并集到一个元组的转换是一个非常糟糕的想法,你不应该尝试去做。让我们先做,然后自责:

    // oh boy don't do this
    type UnionToIntersection<U> =
      (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
    type LastOf<T> =
      UnionToIntersection<T extends any ? () => T : never> extends () => (infer R) ? R : never
    
    // TS4.0+
    type Push<T extends any[], V> = [...T, V];
    
    // TS4.1+
    type TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> =
      true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>
    
    type abc = 'a' | 'b' | 'c';
    type t = TuplifyUnion<abc>; // ["a", "b", "c"] 
    
    //噢,孩子,别这样
    类型UnionToIntersection=
    (U扩展任何?(k:U)=>void:never)扩展((k:inferi)=>void)?I:从来没有
    类型=
    UnionToIntersection T:never>extends()=>(推断R)?R:从来没有
    //TS4.0+
    类型Push=[…T,V];
    //TS4.1+
    类型TuplifyUnion=
    真的吗?[]:推送
    abc类型='a'|'b'|'c';
    类型t=TuplifyUnion

    这种方法很有效,但我真的建议不要将其用于任何官方用途或任何生产代码中。原因如下:

    • 不能依赖于联合类型的排序。这是编译器的一个实现细节;由于
      X | Y
      相当于
      Y | X
      ,因此编译器可以随意更改其中一个。有时它确实:

        type TypeTrue1A = TuplifyUnion<true | 1 | "a">; // [true, 1, "a"] I've sometimes faced a situation in which I want to derive type B from type A but find that either TS does not support it, or that doing the transformation results in code that's hard to follow. Sometimes, the choice of deriving B from A is arbitrary and I could just as well derive in the other direction. Here if you can start with your tuple, you can easily derive a type that covers all the values that the tuple accepts as elements:

      type X = ["a", "b", "c"];
      
      type AnyElementOf<T extends any[]> = T[number];
      
      type AnyElementOfX = AnyElementOf<X>;
      

      类型TypeTrue1A=TuplifyUnion;//[true,1,“a”]我有时会遇到这样一种情况:我想从类型a派生类型B,但发现要么TS不支持它,要么转换后的代码很难理解。有时候,从A导出B的选择是任意的,我也可以从另一个方向导出。在这里,如果您可以从元组开始,就可以轻松派生一个类型,该类型涵盖元组作为元素接受的所有值:

      类型X=[“a”、“b”、“c”]; 类型AnyElementOf=T[number]; 键入AnyElementOfX=AnyElementOf;

      如果你检查
      AnyElementOfX的扩展,你会得到
      “a”|“b”|“c”
      ,我有时会遇到这样的情况,我想从类型a派生类型b,但发现要么TS不支持它,要么转换后的代码很难理解。有时候,从A导出B的选择是任意的,我也可以从另一个方向导出。在这里,如果您可以从元组开始,就可以轻松派生一个类型,该类型涵盖元组作为元素接受的所有值:

      类型X=[“a”、“b”、“c”]; 类型AnyElementOf=T[number]; 键入AnyElementOfX=AnyElementOf;

      如果检查
      AnyElementOfX
      的扩展,将得到
      “a”|“b”|“c”

      联合只能包含一个类型列表中的值。因此,根据定义,不能有包含所有值的并集。你想实现什么?“{a:number,b:number,c:number}”返回'a'|'b'|'c',但我需要元组来制作一些元编程的东西你的实际用例是什么?你能举一个小例子说明你打算如何在代码中使用元组吗?我想把poco对象转换成具有类型安全性的数组。联合只能包含一个类型列表中的值。因此,根据定义,不能有包含所有值的并集。你想实现什么?“{a:number,b:number,c:number}”返回'a'|'b'|'c',但我需要元组来制作一些元编程的东西你的实际用例是什么?你能举个小例子说明你打算如何在你的代码中使用元组吗?我想把poco对象转换成具有类型安全性的数组。我读过关于交叉干扰技巧的书。编译器用反变量推断交集类型,所以它应该用协方差推断并集,对吗?但是这一个不会使intersction类型IntersectionToUnion=(U扩展任何?U[]:从不)扩展(推断I)[]?I:从来没有;为什么?因为条件类型分布在并集上,而不是交集上。目前语言中没有任何东西分布在交叉点上。这可能不好,但有时我们需要将类型转换为元组。例如,第三方库公开了联合类型,我需要一个元组来在我的app@JPS我希望当疯狂的事情发生时,你不要责怪我!我读过关于交叉口干扰技巧的书。编译器用反变量推断交集类型,所以它应该用协方差推断并集,对吗?但是这一个不会使intersction类型IntersectionToUnion=(U扩展任何?U[]:从不)扩展(推断I)[]?I:从来没有;为什么?因为条件类型分布在并集上,而不是交集上。目前语言中没有任何东西分布在交叉点上。这可能不好,但有时我们需要将类型转换为元组。例如,第三方库公开了联合类型,我需要一个元组来在我的app@JPS我希望当疯狂的事情发生时,你不要责怪我!