打字稿从 2 个联合类型生成索引签名类型
typescript generate index signature type from 2 union types
给出
type key = "a" | "b" | "c"
type value = 1 | 2 | 3
我想使用上面的两个联合类型生成 {a:1, b:2, c:3}
type A<K,V> = ?????
什么是?????
从技术上讲,这是可以做到的。
考虑这个例子:
type key = "a" | "b" | "c"
type value = 1 | 2 | 3
// credits goes to
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
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>
我已将 key
和 value
都转换为元组,然后将它们合并。
但是,您不应在生产代码中执行此操作。 不安全。
请看这个 issue/17944 and my question.
你永远不应该像 Object.keys
那样依赖联合秩序。
给出
type key = "a" | "b" | "c"
type value = 1 | 2 | 3
我想使用上面的两个联合类型生成 {a:1, b:2, c:3}
type A<K,V> = ?????
什么是?????
从技术上讲,这是可以做到的。 考虑这个例子:
type key = "a" | "b" | "c"
type value = 1 | 2 | 3
// credits goes to
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
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>
我已将 key
和 value
都转换为元组,然后将它们合并。
但是,您不应在生产代码中执行此操作。 不安全。 请看这个 issue/17944 and my question.
你永远不应该像 Object.keys
那样依赖联合秩序。