如何根据字符串值检查泛型类型映射器是否具有键
how to check if generic type mapper has key according to a string value
我正在尝试弄清楚如何使用通用类型映射器和字符串值:
我有一个名为 getItemsPerKey(itemsMapper : Map, distinctIdsList : number[]) 的函数。K 类型是 数字或字符串。我想检查 string 或 number 的 K 类型值是否相等(或应用 has(key) 扩展函数)到一个特定的字符串值。
这是相关代码:
export class SomeService
{
//currently K can be number or string
getItemsPerKey<K, V>(itemsMapper : Map<K,V[]>, distinctIdsList : number[])
{
let filteredItemsMapper : Map<K, V[]> = new Map();
for (let [key, itemsTypeV] of Object.entries(itemsMapper))
{
if (distinctIdsList.includes(+key))
{
/*This is problematic - "Argument of type 'string' is not assignable to parameter of type 'K'.
'K' could be instantiated with an arbitrary type which could be unrelated to 'string'."*/
if (filteredItemsMapper.has(key))
{
....
}
}
}
}
}
真正的问题是您使用的是 Object.entries()
on itemsMapper
, which is not at all going to do what you want. You are confusing the keys/values held by the map as data, verses the keys/values on the itemsMapper
object itself. You should instead be using Map.prototype.entries()
。也就是说:
- 不要 写
Object.entries(itemsMapper)
❌
- DO 写入
itemsMapper.entries()
✔
为了演示,我们做一个Map<string, number>
来看看:
const testMap = new Map([["a", 1], ["b", 2]]);
其中有两个条目。但是如果我们使用 Object.entries()
,什么也不会发生:
for (let [key, val] of Object.entries(testMap)) {
console.log(key, val) // nothing happens
}
console.log(Object.entries(testMap).length); // 0
嗯,它有 没有 个条目?我以为它有两个。问题是 Object.entries()
是 而不是 遍历地图保存的数据;它遍历地图的 own enumerable 属性。其中有none。我们可以添加一些:
const mapWithAdditionalProp = Object.assign(
new Map([["a", 1], ["b", 2]]),
{ someProperty: "hello" }
);
console.log(mapWithAdditionalProp.someProperty.toUpperCase()); // HELLO
现在 mapWithAdditionalProp
是一个包含这两个条目的映射,但它也有自己的 属性,名为 someProperty
。现在让我们做 Object.entries()
:
for (let [key, val] of Object.entries(mapWithAdditionalProp)) {
console.log(key, val) // "someProperty", "hello"
}
所以,如果我们试图将一些其他属性推到地图对象本身,那就太好了。但是,如果您试图真正获取地图中的数据,那就太糟糕了。
另一方面,Map.prototype.entries()
正是为了遍历地图保存的数据:
for (let [key, val] of testMap.entries()) {
console.log(key, val) // "a", 1 ; "b", 2
}
所以你应该使用 itemsMapper.entries()
而不是 Object.entries(itemsMapper)
。当你这样做时:
class SomeService {
//currently K can be number or string <-- then you should constrain it to be such
getItemsPerKey<K extends string | number, V>(
itemsMapper: Map<K, V[]>,
distinctIdsList: number[]
) {
let filteredItemsMapper: Map<K, V[]> = new Map();
for (let [key, itemsTypeV] of itemsMapper.entries()) {
if (distinctIdsList.includes(+key)) {
if (filteredItemsMapper.has(key)) {
}
}
}
}
}
编译没有错误。万岁!更好的是,它可能会在运行时执行您想要的操作。
请注意,string
与 K
问题间接地告诉了您问题所在。 JavaScript 中的对象只有 string
(或 symbol
)键。 Object.entries()
只给你 string
键。所以 Object.entries(itemsMapper)
将给你一个数组对,其中每对中的第一个项目是 string
。你得到 Array<[string, any]>
.
但是 Map<K, V>
可以是任何类型,如 K
;它可以使用 string
s 或 number
s 或 Date
s 作为键(尽管在 Map
中使用对象作为键通常不是人们想要做的,因为它们被比较引用)。当您调用 itemsMapper.entries()
时,您会得到 IterableIterator<[K, V[]]>
(它不是一个数组,但您可以像一个数组一样对其进行迭代),并且每对中的第一项是 K
,如您所愿。
所以修复不是用has()
强制检查string
键;而是检查正确的密钥类型。
我正在尝试弄清楚如何使用通用类型映射器和字符串值:
我有一个名为 getItemsPerKey
这是相关代码:
export class SomeService
{
//currently K can be number or string
getItemsPerKey<K, V>(itemsMapper : Map<K,V[]>, distinctIdsList : number[])
{
let filteredItemsMapper : Map<K, V[]> = new Map();
for (let [key, itemsTypeV] of Object.entries(itemsMapper))
{
if (distinctIdsList.includes(+key))
{
/*This is problematic - "Argument of type 'string' is not assignable to parameter of type 'K'.
'K' could be instantiated with an arbitrary type which could be unrelated to 'string'."*/
if (filteredItemsMapper.has(key))
{
....
}
}
}
}
}
真正的问题是您使用的是 Object.entries()
on itemsMapper
, which is not at all going to do what you want. You are confusing the keys/values held by the map as data, verses the keys/values on the itemsMapper
object itself. You should instead be using Map.prototype.entries()
。也就是说:
- 不要 写
Object.entries(itemsMapper)
❌ - DO 写入
itemsMapper.entries()
✔
为了演示,我们做一个Map<string, number>
来看看:
const testMap = new Map([["a", 1], ["b", 2]]);
其中有两个条目。但是如果我们使用 Object.entries()
,什么也不会发生:
for (let [key, val] of Object.entries(testMap)) {
console.log(key, val) // nothing happens
}
console.log(Object.entries(testMap).length); // 0
嗯,它有 没有 个条目?我以为它有两个。问题是 Object.entries()
是 而不是 遍历地图保存的数据;它遍历地图的 own enumerable 属性。其中有none。我们可以添加一些:
const mapWithAdditionalProp = Object.assign(
new Map([["a", 1], ["b", 2]]),
{ someProperty: "hello" }
);
console.log(mapWithAdditionalProp.someProperty.toUpperCase()); // HELLO
现在 mapWithAdditionalProp
是一个包含这两个条目的映射,但它也有自己的 属性,名为 someProperty
。现在让我们做 Object.entries()
:
for (let [key, val] of Object.entries(mapWithAdditionalProp)) {
console.log(key, val) // "someProperty", "hello"
}
所以,如果我们试图将一些其他属性推到地图对象本身,那就太好了。但是,如果您试图真正获取地图中的数据,那就太糟糕了。
另一方面,Map.prototype.entries()
正是为了遍历地图保存的数据:
for (let [key, val] of testMap.entries()) {
console.log(key, val) // "a", 1 ; "b", 2
}
所以你应该使用 itemsMapper.entries()
而不是 Object.entries(itemsMapper)
。当你这样做时:
class SomeService {
//currently K can be number or string <-- then you should constrain it to be such
getItemsPerKey<K extends string | number, V>(
itemsMapper: Map<K, V[]>,
distinctIdsList: number[]
) {
let filteredItemsMapper: Map<K, V[]> = new Map();
for (let [key, itemsTypeV] of itemsMapper.entries()) {
if (distinctIdsList.includes(+key)) {
if (filteredItemsMapper.has(key)) {
}
}
}
}
}
编译没有错误。万岁!更好的是,它可能会在运行时执行您想要的操作。
请注意,string
与 K
问题间接地告诉了您问题所在。 JavaScript 中的对象只有 string
(或 symbol
)键。 Object.entries()
只给你 string
键。所以 Object.entries(itemsMapper)
将给你一个数组对,其中每对中的第一个项目是 string
。你得到 Array<[string, any]>
.
但是 Map<K, V>
可以是任何类型,如 K
;它可以使用 string
s 或 number
s 或 Date
s 作为键(尽管在 Map
中使用对象作为键通常不是人们想要做的,因为它们被比较引用)。当您调用 itemsMapper.entries()
时,您会得到 IterableIterator<[K, V[]]>
(它不是一个数组,但您可以像一个数组一样对其进行迭代),并且每对中的第一项是 K
,如您所愿。
所以修复不是用has()
强制检查string
键;而是检查正确的密钥类型。