如何获得TypeScript映射类型的逆函数?

时间:2019-11-26 20:10:43

标签: typescript typescript-generics mapped-types

我正在寻找TypeScript映射类型的“逆”(其属性严格是字符串,因此是“不可逆的”)。为了说明我想要的结果,我需要一个通用的type

type Inverse<M> = ...

能够变形

type MappedType = {
  key1: 'value1'
  key2: 'value2'
};

进入

/**
 * {
 *   value1: 'key1';
 *   value2: 'key2';
 * }
 */
type MappedTypeInverse = Inverse<MappedType>

我已经尝试了几件事。.但无济于事:

type Inverse<M> = M extends Record<infer O, infer T> ? Record<T, O> : never;

/**
 * type MappedTypeInverse = {
 *   value1: 'key1' | 'key2'
 *   value2: 'key2' | 'key2'
 * }
 */
type MappedTypeInverse = Inverse<MappedType>
type InverseValue<M extends Record<any, any>, V extends M[keyof M]> = V extends M[infer K] ? K : never;

/**
 * type MappedTypeInverseValue = unknown // expecting 'key1'
 */
type MappedTypeInverseValue = InverseValue<MappedType, 'value1'>

这甚至可能吗?任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:2)

这是您可以完成此操作的方法。它从this answer借用了一些“恶魔”,以在过程的中间步骤将并集转换为交集:

length = len(mylist) # If len(os.listdir('.')) is greater than len(mylist),
# replace mylist with os.listdir('.')

imageList = os.listdir('.')
iterations = 2 # The number of time you want this to run
for i in range(0,iterations):
    for x in range(0, length):
        api.update_with_media(imageList[x], mylist[num])

此方法的另一个好处是,当输入记录包含重复的属性值时,它将输出具有适当属性值type MappedType = { key1: 'value1'; key2: 'value2'; }; type Intermediate<R extends Record<string, string>> = R extends Record<infer K, string> ? { [P in K]: { [Q in R[P]]: P; }; } : never; type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; type Inverse<R extends Record<string, string>> = Intermediate<R> extends Record<string, infer T> ? { [K in keyof UnionToIntersection<T>]: UnionToIntersection<T>[K]; } : never; type InverseMappedType = Inverse<MappedType>; // type InverseMappedType = { // value1: 'key1'; // value2: 'key2'; // } 的映射类型:

never

在TypeScript中比我更精通的人可能知道一个比此短的方法来反转映射类型,但这似乎至少可以完成工作。

答案 1 :(得分:2)

这是一个精简的alternative(除了Patrick Robert的出色解决方案):

type KeyFromVal<T, V> = {
  [K in keyof T]: V extends T[K] ? K : never
}[keyof T];

// we assume the type to be an object literal with string values
// , should also work with number or symbol
type Inverse<M extends Record<string, string>> = {
  [K in M[keyof M]]: KeyFromVal<M, K>
};

type MappedType = {
  key1: 'value1'
  key2: 'value2'
};

type MappedTypeInverse = Inverse<MappedType> // { value1: "key1"; value2: "key2"; }