【问题标题】:TypeScript: Copy Map while adding a key-value-pair at the same timeTypeScript:复制地图,同时添加键值对
【发布时间】:2019-05-27 17:27:35
【问题描述】:

我想优雅地复制一个打字稿结构interfaceName(满足某个接口)。此 TypeScript 包含类型为 Map<IKey, number> 的映射 attribute3,可能需要修改(取决于条件):必须插入额外的键值对。

IKey 同样是一个接口。

interface InterfaceName{
   attribute1: string
   attribute2: string
   attribute3: Map<IKey, number>

}

interface IKey{
    a1: number
    a2: number
}

}

我的尝试如下:我只是使用... 语法复制interfaceName 的所有成员,然后尝试为attribute3 分配修改后的副本。 但不知何故,这不起作用:最后,无论布尔值如何,相同的 Map 对象都会从函数中传递出去。

const createModifiedCopyIfWished = (interfaceName: InterfaceName, wished: Boolean) => wished ? {
        ...interfaceName,
        attribute3: interfaceName.attribute3.set({a1:1,a2:2},5)
    }
    :
    interfaceName

let a: InterfaceName = {
    attribute1: "a",
    attribute2: "b",
    attribute3: new Map<IKey, number>()
}

let b = createModifiedCopyIfWished(a, true)

// {"attribute1":"a","attribute2":"b","attribute3":{}}
console.log(JSON.stringify(b))

探测方法是什么? 甚至可以在一个语句中实现吗?

工作示例:LiveCode

【问题讨论】:

  • 当你说“不知何故这不起作用”时,你是什么意思?两个InterfaceName 对象共享一个共同的Map 实例并且您希望它们是不同的实例?这里发生了很多事情可能会给您带来麻烦(例如,您的 IKey 不是一个很好的密钥类型)并且很难与无法编译的代码(什么是 {1,2})分开并且没有除了“不起作用”之外的问题描述。请尝试将其编辑为minimal reproducible example,以便有人可以帮助您。干杯!
  • 感谢您的反馈。我更正了代码并清楚地指定了不工作的东西。我看到 IKey 不是一个很好的键类型(因为它可以有更多的属性来生成不同的键),因此,我会考虑将它作为一个类。

标签: typescript typescript3.0


【解决方案1】:

是的,应该可以用一个语句,比如

const createModifiedCopyIfWished = (
  interfaceName: InterfaceName, 
  wished: boolean
) => wished ? {
  ...interfaceName,
  attribute3: new Map(
    [...Array.from(interfaceName.attribute3), [{ a1: 1, a2: 2 }, 123]]
  )
} : interfaceName

这是假设您尝试clone 地图,而不仅仅是修改现有地图。


请注意,不过,IKey 对于Map 来说可能不是一个好的key typeMap 使用 object equality 基于身份(内存中完全相同的对象)而不是任何类型的“相同属性”相等性。因此,以下行为不会像人们预期的那样:

const map: Map<IKey, number> = new Map();
map.set({ a1: 1, a2: 2 }, 123);
const val = map.get({ a1: 1, a2: 2});
console.log(val); // undefined !

这是因为({a1: 1, a2: 2} === {a1: 1, a2: 2})false。除非您非常小心,否则将对象用作映射键是丢失它们的好方法。对象作为映射键起作用的唯一方法是将实际对象键存储在某处并稍后使用它们来查找映射中的条目。这通常不是人们想要的。

更合理的行为可能只是使用 string 作为您的密钥,并在将其放入地图或查找之前将您的预期密钥转换为 JSON.stringify(objectKey) 之类的东西。


无论如何希望这会有所帮助。祝你好运。

【讨论】:

  • 感谢您的快速答复!是否也可以使用普通构造函数(如链接页面上所示)并在创建的对象上调用 .set ?关于钥匙:我真的没想到。所以不使用同一个对象根本不可能吗?又一次,一个新的字符串是内存中的另一个对象?字符串化的东西会很丑陋...
  • 您可以使用常规构造函数并根据需要调用set,是的。我猜这看起来也更好:attribute3: new Map(interfaceName.attribute3).set({ a1: 1, a2: 2 }, 123)。至于键:字符串比较相等是基于字符串的值,而不是对象的身份。所以"foo" === "foo"true。这绝对是丑陋的,我同意。 JavaScript 没有具有用户定义相等性的本机 Map。请参阅this question 了解更多信息
  • 我不知道,我好像错过了什么。如果我从这里的 cmets 获取我的代码、您的代码或花哨的版本,那么任何一个都不起作用。您可以在我的帖子末尾找到 typescriptlang.com/play 的链接。
  • 你不能JSON.stringify()Map。尝试检查实际的地图条目,或执行JSON.stringify(Array.from(b.attribute3)) 之类的操作
  • ...所以它立即工作(除了它不是副本,而是修改后的源)...我被 Redux Dev Tools 愚弄了。谢谢,你帮了大忙。
猜你喜欢
  • 2021-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-04
  • 1970-01-01
  • 2011-04-16
相关资源
最近更新 更多