我尝试为打字稿中的哈希映射创建一个强大的打字界面。
哈希图包含带有动态字符串名称的键。还有一个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
会干扰动态密钥。
如何获得我们所需要的强类型?
答案 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[]
};
在T
和K
(T
类型的键)中都是通用的。您可以使用类型推断来实例化T
和K
,如下所示:
// 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">
。有帮助吗?祝你好运!