【问题标题】:typescript generate index signature type from 2 union types打字稿从 2 个联合类型生成索引签名类型
【发布时间】:2021-12-07 18:57:29
【问题描述】:

给定

type key = "a" | "b" | "c"
type value = 1 | 2 | 3

我想使用上面的两种联合类型生成{a:1, b:2, c:3}

type A<K,V> = ?????

什么是?????

【问题讨论】:

  • 我不相信 TypeScript 中的联合类型是有序的,所以我认为没有办法直接做你想做的事情,而不需要手动添加一些关于不同值如何可用的更多信息每种类型都链接在一起。
  • @MarkHanna 是对的。 Unions 是无序的数据结构。你需要使用元组来代替

标签: typescript mapped-types


【解决方案1】:

技术上是可以做到的。 考虑这个例子:

type key = "a" | "b" | "c"
type value = 1 | 2 | 3

// credits goes to https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
  k: infer I
) => void
  ? I
  : never;

// credits goes to https://github.com/microsoft/TypeScript/issues/13298#issuecomment-468114901
type UnionToOvlds<U> = UnionToIntersection<
  U extends any ? (f: U) => void : never
>;

type PopUnion<U> = UnionToOvlds<U> extends (a: infer A) => void ? A : never;

// credits goes to https://stackoverflow.com/questions/53953814/typescript-check-if-a-type-is-a-union#comment-94748994
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;

type UnionToArray<T, A extends unknown[] = []> = IsUnion<T> extends true
  ? UnionToArray<Exclude<T, PopUnion<T>>, [PopUnion<T>, ...A]>
  : [T, ...A];

type Length<T extends ReadonlyArray<any>> = T extends { length: infer L }
  ? L
  : never;

type CompareLength<
  X extends ReadonlyArray<any>,
  Y extends ReadonlyArray<any>
  > = Length<X> extends Length<Y> ? true : false;


type Callback<T, U> = T extends PropertyKey ? U extends PropertyKey ? Record<T, U> : never : never

// https://catchts.com/tuples#zip 
type Zip<
  T extends ReadonlyArray<any>,
  U extends ReadonlyArray<any>,
  Result extends Record<string, any> = {}> =
  (CompareLength<T, U> extends true
    ? (T extends []
      ? Result
      : (T extends [infer HeadT1]
        ? (U extends [infer HeadU1]
          ? Result & Callback<HeadT1, HeadU1>
          : never)
        : (T extends [infer HeadT2, ...infer TailT2]
          ? (U extends [infer HeadU2, ...infer TailU2]
            ? Zip<TailT2, TailU2, Result & Callback<HeadT2, HeadU2>>
            : never)
          : never
        )
      )
    )
    : never);



type Keys = UnionToArray<key>;

type Values = UnionToArray<value>

// Record<"a", 1> & Record<"b", 2> & Record<"c", 3>
type Result = Zip<Keys, Values>

Playground

我已将 keyvalue 都转换为元组,然后将它们合并。

但是,您不应在生产代码中执行此操作。这是不安全。 请看这个issue/17944 和我的question

您永远不应该依赖联合订单以及Object.keys 订单。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-06
    • 2017-05-18
    • 2021-01-07
    相关资源
    最近更新 更多