无法在TypeScript中为Map <tkey,tvalue [] =“”>编写扩展方法

时间:2018-11-29 20:07:55

标签: angular typescript generics

我是Angular / TS的新用户,并且喜欢使用Extension方法。他们在标准类型上做得很好,但是现在我正在尝试为Map编写一个其中V将被数组化的模型,但是不幸的是它似乎不起作用。

我要尝试的是,该扩展方法会将地图V初始化为数组,然后推送值或如果已经初始化则推送。

declare global {
interface Map<TKey, TValue[]>
 {
    SetInArray(key:TKey, value:TValue):boolean;
 }
}


Map.prototype.SetInArray = function<TKey, TValue>(key:TKey, value:TValue):boolean {

let isNew:boolean = false;

if(this.has(key) == false){

    this.set(key, []);

    isNew = true;

}

let items:TValue[] = this.get(key);

items.push(value);

return isNew;
};


export {};

请告知

谢谢

1 个答案:

答案 0 :(得分:4)

存在一些问题(除了普遍的知识是you should not extend native object prototypes之外)。第一个是声明通用接口或类型时,其类型参数必须是裸名,而不是其他类型的函数。所以你不能拥有

interface Foo<T, U[]> {} // error

如果要求第二个类型参数为数组,则应使用generic constraint

interface Foo<T, U extends any[]> {} // okay

下一个问题是,如果以任何方式更改类型参数或其约束,则无法merge declarationsMap<K, V>已在the standard library中定义,因此您不能将其更改为Map<TKey, TValue[]>Map<TKey, TValue extends any[]>甚至Map<K, V extends any[]>。您只需将其保留为Map<K, V>

您要添加的新方法要求V为数组类型才能有意义。而且您不能在声明中约束V。你被卡住了吗?没有!幸运的是,您可以使用称为this parameter的TypeScript功能。这个想法是,您可以在函数或方法的参数列表的开头添加一个名为this的参数。当您调用该方法时,您不会使用this参数,但是TypeScript将强制您仅在其this上下文匹配的对象上调用该方法。

像这样:

// no error
declare global {
  interface Map<K, V> {
    SetInArray<V>(this: Map<K, V[]>, key: K, value: V): boolean;
  }
}

Map.prototype.SetInArray = function <K, V>(this: Map<K, V[]>, key: K, value: V): boolean {
  let isNew: boolean = false;
  if (this.has(key) == false) {
    this.set(key, []);
    isNew = true;
  }
  let items: V[] = this.get(key)!;
  items.push(value);
  return isNew;
};

让我们尝试一下:

const numberArrayMap = new Map<string, number[]>();
numberArrayMap.set("a", [1, 2, 3])
numberArrayMap.SetInArray("a", 4); // okay

const numberMap = new Map<string, number>();
numberMap.set("a", 4)
numberMap.SetInArray("a", 4); // error
// The 'this' context of type 'Map<string, number>' is not assignable 
// to method's 'this' of type 'Map<string, number[]>'. 
// Type 'number' is not assignable to type 'number[]'.

我认为这正是您想要的行为。请注意,numberArrayMap如何让您调用SetInArray(),而numberMap却没有,并且错误告诉您即使Map确实具有SetInArray方法,您也可以由于this上下文不兼容而无法调用它。

好的,希望能有所帮助。祝你好运!