打字稿:在地图中使用日期作为键?

Posted

技术标签:

【中文标题】打字稿:在地图中使用日期作为键?【英文标题】:Typescript: using Date as key in Map? 【发布时间】:2020-04-08 07:04:57 【问题描述】:

在我的应用程序中,我需要每个日期的对象地图。由于 typescript 有一个 Map 和一个 Date 对象,我希望这很简单。

  let map: Map<Date, MyObject> = new Map<Date, MyObject>();

并使用set 添加新的键和值对。但后来我意识到我不能get 使用日期的值,除非我使用完全相同的Date 实例。

我已经用它编写了一个单元测试:

  it('Should not be a problem', () => 
      let d1: Date = new Date(2019, 11, 25);    // Christmas day
      let d2: Date = new Date(2019, 11, 25);    // Same Christmas day?

      let m: Map<Date, string> = new Map<Date, string>();
      m.set(d1, "X");

      expect(m.get(d1)).toBe("X");   // <- This is OK.
      expect(m.get(d2)).toBe("X");   // <- This test fails.
  );

为什么我无法从地图中获取值,除非我使用完全相同的实例?

【问题讨论】:

我认为m.get(d2) 行不行,因为 Map 将每个 Date 键存储为单独的对象,无论它们是否是同一个 Date 实例。我建议将日期实例转换为字符串(例如使用方法toDateString()),你会得到它。 你的意思是Date之间不相等? 不是真的,因为它们是对象,相等运算符检查它们是否是同一个实例。看看this post 【参考方案1】:

最好使用原始值(数字、字符串)作为 Map 键:

let m: Map<string, string> = new Map<string, string>();

let d1: Date = new Date(2019, 11, 25);    // Christmas day
let d2: Date = new Date(2019, 11, 25);    // Same Christmas day?

m.set(d1.toDateString(), "X");

console.log(d1.toDateString())
console.log(d2.toDateString())
console.log(m.get(d2.toDateString()))

我在上述 cmets 上提供了此类行为的链接。

【讨论】:

【参考方案2】:

这总是虚假的,因为这两个日期对象是不同的可变 javascript 对象。

new Date(2019, 11, 25) === new Date(2019, 11, 25) ==&gt; false.

您可以在post 中查看答案。

【讨论】:

【参考方案3】:

这是Map的核心逻辑,正如你所知,map将值存储在键值对中。

对于键的比较,键应始终具有相同的引用。您可能知道字符串字面量引用在许多编程语言中是相等的,因此在 map 中首选使用字符串作为键。

上述行为不仅适用于date,也适用于任何其他可变对象类型。

例如

let str1 = 'test';
let str2 = 'test';
str1 == str2; // true

let str1 = new String('test');
let str2 = new String('test');
str1 == str2; // false

map获取值时,不考虑keys数据,而是key的唯一标识是search。当您创建不可变对象时,每个对象可能具有相同的数据,但每个对象的引用会有所不同。因此它将被视为不同的键。

解决方案是使用可以在整个程序中具有相同引用的类型,例如字符串文字。

再举一个例子,

class Demo 
  field: string;
  constructor(f: string) 
    this.field = f;
  


const d1 = new Demo('test');
const d2 = new Demo('test');

// both objects seems same by data, but there references are different
// hence will be treated as separate keys.
const m: Map<any, string> = new Map<any, string>();
m.set(d1, 'value1');

console.log(m.get(d1)); // value1
console.log(m.get(d2)); // undefined

【讨论】:

问题不在于可变性,而在于平等。可变性仅在等式检查依赖于可以更改的数据的 map 实现中很重要。 JavaScript 的Map 使用引用相等,即使对象发生了变异,它也不会改变,因此您可以在不破坏Map 的情况下拥有可变的对象键。不幸的是,这也意味着当您使用Map 时,您必须持有对象键,因为无法获得与旧对象相等的新对象。 @jcalz 同意。更新了我的答案。你觉得现在有意义吗? 是的,谢谢。如果有人关心我持有可变键的意思,here's an example。

以上是关于打字稿:在地图中使用日期作为键?的主要内容,如果未能解决你的问题,请参考以下文章

在打字稿中使用枚举作为接口键

从打字稿中的地图检索值时,map.get 不是函数

打字稿 - 类型'值:数字;日期:日期; ' 不可分配给类型 'Record[]'。 ts(2322)

如何从打字稿中的json响应中获取日期对象

开玩笑的打字稿 - 模拟日期构造函数

类型“数字”不可分配给类型“日期” - 打字稿未编译