在TypeScript中实现扩展元数据的ES6映射
我需要一个映射,其中一个键不仅与值关联,还与一些元数据关联,比如“权重”或“timeToLive” 首先,一个示例界面,用于保存不同权重的项目:在TypeScript中实现扩展元数据的ES6映射,typescript,dictionary,generics,Typescript,Dictionary,Generics,我需要一个映射,其中一个键不仅与值关联,还与一些元数据关联,比如“权重”或“timeToLive” 首先,一个示例界面,用于保存不同权重的项目: 导出接口{ 重量:数字 } …和类型别名,用于将所有元数据接口与要保存在映射中的实际值合并: 类型AugmValue=M&{ 值:V; } 我拿着内置的地图,把它扩展了。对于泛型类型: M表示元数据接口,如Weighted&Ttl K是一种钥匙 V是一种实际值 。。。和执行: 导出类MdaMap扩展映射{ 构造函数(记录:[K,V,M][]=[
导出接口{
重量:数字
}
…和类型别名,用于将所有元数据接口与要保存在映射中的实际值合并:
类型AugmValue=M&{
值:V;
}
我拿着内置的地图,把它扩展了。对于泛型类型:
- M表示元数据接口,如
Weighted&Ttl
- K是一种钥匙
- V是一种实际值
导出类MdaMap扩展映射{
构造函数(记录:[K,V,M][]=[]{
常量结果:[K,AugmValue][]=[];
for(记录的常量[键、值、元]){
push([key,Object.assign({value:val},meta)]);
}
超级(结果);
}
get(key:K):V |未定义{
const t=super.get(键);
返回typeof t===“未定义”?未定义:t.value;
}
}
但是,get
会在长消息下面加下划线,结尾为:
Type 'V' is not assignable to type 'AugmValue<V, M>'.
Type 'V' is not assignable to type 'M'.
如果扩展Map
,则需要实现扩展,这意味着get(key:K)
需要返回AugmValue>|未定义的
,而不是V |未定义的
您可以使用的一种可能性是get()
方法,以便它仍然实现所需的签名,但也接受一个附加参数来提供额外的行为:
export class MdaMap<M, K, V> extends Map<K, AugmValue<V, M>> {
get(key: K): AugmValue<V, M> | undefined;
get<AK extends keyof AugmValue<V, M>>(
key: K,
augmentedValueKey: AK
): AugmValue<V, M>[AK] | undefined;
get<AK extends keyof AugmValue<V, M>>(
key: K,
augmentedValueKey?: AK
): AugmValue<V, M> | AugmValue<V, M>[AK] | undefined {
const t = super.get(key);
return typeof augmentedValueKey === 'undefined' ? t :
typeof t === 'undefined' ? undefined : t[augmentedValueKey];
}
}
const mdaMap = new MdaMap([["a", true, { weight: 4 }], ["b", false, { weight: 17 }]]);
const augmented = mdaMap.get("a"); // AugmValue<boolean, Weighted> | undefined
const unaugmented = mdaMap.get("a", "value"); // boolean | undefined
const weight = mdaMap.get("a", "weight"); // number | undefined
这太痛苦了,我想知道你是否应该只使用Map
,而不尝试创建一个新类
无论如何,希望这些想法中的一个能给你一些帮助。祝你好运 谢谢你详尽的回答。我考虑了两种方法。首先是扩展地图-正如您所想象的,这个解决方案是不受欢迎的,令人困惑的。所以第二个选择是围绕地图创建包装器-但正如您所注意到的,它很乏味而且。。。不愉快的不过,我还是希望有一个干净、无痛的界面,所以使用
Map
并不能让我满意。然而,我想知道重新实现Map是否不是一条可行之路。我打算询问关于SO的实施细节,我会看看的。再次感谢您的回答,这很有启发性
class OtherMap<M, K, V> {
private innerMap: Map<K, AugmValue<V, M>> = new Map();
constructor(records: [K, V, M][] = []) {
this.innerMap = new Map(records.map(
([k, v, m]) => [k, Object.assign({ value: v }, m)] as [K, AugmValue<V, M>]
));
}
clear(): void {
return this.innerMap.clear();
}
delete(key: K): boolean {
return this.innerMap.delete(key);
}
forEach(callbackfn: (value: M & { value: V; }, key: K, map: OtherMap<M, K, V>) => void, thisArg?: any): void {
return this.innerMap.forEach((v, k) => callbackfn(v, k, this), thisArg);
}
get(key: K): V | undefined {
return (this.innerMap.get(key) || { value: undefined }).value;
}
has(key: K): boolean {
return this.innerMap.has(key);
}
set(key: K, value: M & { value: V; }): this {
this.innerMap.set(key, value);
return this;
}
get size(): number {
return this.innerMap.size;
}
[Symbol
.iterator](): IterableIterator<[K, M & { value: V; }]> {
return this.innerMap[Symbol.iterator]();
}
entries(): IterableIterator<[K, M & { value: V; }]> {
return this.innerMap.entries();
}
keys(): IterableIterator<K> {
return this.innerMap.keys();
}
values(): IterableIterator<M & { value: V; }> {
return this.innerMap.values();
}
[Symbol.toStringTag]: "Map";
}