泛型键入带有动态键和T数组的哈希图

时间:2018-10-21 08:51:04

标签: typescript

我尝试为打字稿中的哈希映射创建一个强大的打字界面。

哈希图包含带有动态字符串名称的键。还有一个values,其中包含一个通用类型的数组。

我尝试使用以下界面:

export interface DynamicHashmap<T> {
  [dynamicKey: string]: string;
  values: T[];
}

但它不会编译并继续抱怨:

  

[ts]类型“ T []”的属性“值”不能分配给字符串索引类型“字符串”。

与此类型对应的生成值的示例,该值根据对象属性(此处为User.group)对值进行分组。 dynamicKey在这里解析为group

const user1: User = { id: 'userValue1', group: 'someGroupId' };
const user2: User = { id: 'userValue2', group: 'someGroupId' }; 
const result = {
  group: 'someGroupId',
  values: [
    { id: 'userValue1', group: 'someGroupId' },
    { id: 'userValue2', group: 'someGroupId' }
  ]
}

我猜想静态values会干扰动态密钥。

如何获得我们所需要的强类型?

2 个答案:

答案 0 :(得分:2)

正确的界面是这个

export interface DynamicHashmap<T> {
  [key: string]: string | T[];
  values: T[];
}

这是因为[key: string]代表所有键的签名。这就是为什么它被称为索引签名

您可能对这种界面不太满意,这就是为什么您应该重新考虑它是类似以下内容的原因:

export interface DynamicHashmap<T> {
  dynamicKey: string;
  dynamicValue: string;
  values: T[];
}

答案 1 :(得分:1)

通常,当我听到“动态”时,我会尝试理解这是“仅在运行时已知”还是“在编译时已知但在不同位置具有不同值”。如果是前者,那么您必须使用非常宽泛的类型(例如您正在谈论的字符串索引的东西)...如果是后者,则有时可以使用泛型来表达更窄的类型。例如,在您的情况下:

type DynamicHashMap<T, K extends keyof T> = Pick<T, K> & {values: T[]};

type DynamicHashMap<T, K extends keyof T> = { 
  [P in K | 'values']: P extends K ? T[K] : T[] 
};

TKT类型的键)中都是通用的。您可以使用类型推断来实例化TK,如下所示:

// for example
function makeDynamicHashMap<T, K extends keyof T>(
  key: K, 
  value: T[K], 
  values: T[]
): DynamicHashMap<T, K> {
  return { [key]: value, values: values.filter(v => v[key] === value) } as any;
}

const result = makeDynamicHashMap("group", "someGroupId", [user1, user2]);
result.group; // string
result.values; // User[]

因此,推断result为类型DynamicHashMap<User, "group">。有帮助吗?祝你好运!