Is it possible to use Date as a key in a Typescript Map?

Within my application, I have a requirement for mapping objects according to specific dates. Given that typescript provides both the Map and Date objects, I initially assumed this task would be straightforward.

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

I thought I could simply utilize the set method to insert new key-value pairs. However, upon implementation, I discovered that retrieving values using date keys required the exact same instance of Date.

To verify this behavior, I wrote a unit test:

  it('Experiencing an Issue', () => {
      let d1: Date = new Date(2019, 11, 25);    // Christmas day
      let d2: Date = new Date(2019, 11, 25);    // The same Christmas day?

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

      expect(m.get(d1)).toBe("X");   // <- This works fine.
      expect(m.get(d2)).toBe("X");   // <- This test fails.
  });

This raises the question, why is it necessary to use the precise same instance in order to retrieve a value from the map?

Answer №1

The reason it will always be falsy is because each of the date objects being compared are unique mutable javascript objects.

For example,

new Date(2020, 5, 10) === new Date(2020, 5, 10) ==> false
.

If you want to learn more about this topic, check out this helpful post.

Answer №2

In the realm of programming, the core logic of a Map revolves around storing values in key-value pairs.

When it comes to comparing keys, they must always be of the same reference. In many programming languages, string literal references are considered equal, making strings a preferred choice as keys in maps.

This behavior extends beyond just date objects and applies to any other mutable object type.

For example:

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

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

When retrieving a value from a map, the actual data of the keys is not important. What matters is the unique identity of the key being searched for. Immutable objects may contain the same data, but if their references are different, they will be treated as separate keys.

To ensure consistency throughout your program, opt for types that maintain the same references, like string literals.

Consider one more example:

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

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

// Both objects appear identical in terms of data, but their references differ.
// Therefore, they will be treated as distinct 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

Answer №3

It's recommended to use primitive values like numbers or strings as keys in a Map:

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

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

myMap.set(date1.toDateString(), "X");

console.log(date1.toDateString())
console.log(date2.toDateString())
console.log(myMap.get(date2.toDateString()))

You can find more information about this behavior in the comments above.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

encountering difficulties resolving dependency tree when attempting to generate a new Angular project

Today, I attempted to start a new Angular project using the command ng new <projectname>, but encountered the following error: npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: [email protected] npm ERR! Foun ...

"I am having trouble calling the useStyles function in React with Typescript and Material-

There seems to be a problem with calling the useStyles function as it is throwing the following error message: This expression is not callable. Type 'never' has no call signatures.ts(2349) const useStyles: never Below is the complete code snip ...

"Customizing the properties of an Angular Material mat-slide-toggle: A step-by-step

<mat-slide-toggle>Slide Me!</mat-slide-toggle> https://i.stack.imgur.com/p1hzD.png https://i.stack.imgur.com/aCzs1.png Is it possible to customize the toggle-thumb-icon to increase its length and position it at the end of the bar? ...

There was a serious issue: The mark-compacts were not working effectively near the heap limit, resulting in allocation failure - the JavaScript heap ran out of memory during the

I recently set up a t2.micro server on AWS and encountered an issue when running our application with the command "sudo npm start". The error message I received was: "FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript he ...

Sending geographic coordinates from a child component in a React application using Google Maps to its parent component within a functional

My current project involves creating a map component in my React application using @googlemaps/react-wrapper. I followed the example from Google Maps and successfully added an event to refresh coordinates when dragging the marker. Now, I need to call the m ...

Continuously apply the template in a recursive manner in Angular 2 without reintroducing any duplicated components

Recently, I delved into the world of angular 2 and found it to be quite fascinating. However, I'm currently facing a roadblock and could really use some assistance. The scenario is as follows: I am working on creating a select box with checkboxes in ...

Confirm inclusion in the dictionary using an if statement

This code is designed to check whether the user-provided name and code match values stored in a dictionary. If there is a match, the code will display a welcoming message, but if there is a discrepancy, the 'else' statement will be executed. nam ...

Start up a server using Angular along with Node.js and Express framework

I am encountering an issue with configuring Express as a server in my Angular application. The app loads without any issues when accessing the HOME route, but when trying to access another route, I receive an error message: Cannot GET / This is how I hav ...

The attribute 'body' cannot be found in the specified 'Request' type

Why does the req variable of type Request not show intellisense for the property body? Could this be related to typings? import { Request, Response } from 'express' import { ok, bad } from './responses' export const signIn: async (req ...

Troubleshooting Angular 5 curly brackets problems

Upon updating my app from Angular v2 to v5, I encountered a strange issue with template curly braces. When a template element includes curly braces, nothing would be displayed without any errors in the console. <span>{{ 1 + 1 }}</span> <spa ...

Encountering issues with compiling files in react app using webpack, failing to compile as anticipated

When it comes to compiling, I prefer using webpack with TypeScript files. In my webpack.config.js file: module.exports = async (env, options) => { const dev = options.mode === "development"; const config = { //Webpack configuration pr ...

Issue: Unable to locate the module 'nexmo' & error TS2307: 'nexmo' module not found

Currently, I am utilizing the powerful NestJs Framework alongside typescript. My task involves incorporating two-factor authentication (SMS) using the Nexmo node library. You can find further information on their website: During the development phase, ev ...

Utilizing Angular 2's ngForm template reference variable for input binding

Currently, I am in the process of developing a component with an input called 'valid.' Everything runs smoothly when I bind the value to a parent component member. However, when I attempt to bind it to a template reference as shown below: <st ...

The issue arises when attempting to use the search feature in Ionic because friend.toLowerCase is not a valid function

I keep encountering an error message that says "friend.toLowerCase" is not a function when I use Ionic's search function. The unique aspect of my program is that instead of just a list of JSON items, I have a list with 5 properties per item, such as f ...

Unable to add data to an Array once subscribed to BehaviorSubject

Hello everyone, this is my first time asking a question here. I hope it's clear enough for you to understand :) Let's dive straight into the issue at hand. I have a query regarding a behaviorSubject variable in TypeScript that is not allowing me ...

Issue with Angular4: Unable to select [selected] attribute on initial load

Here is a code snippet to select a department: <select name="department" class="form-control select" [(ngModel)]="departments" formControlName="departmentControl"> <option *ngFor="let department of departments" [ngValue]="department" [se ...

When the URL is entered manually, there appears to be some unusual behavior with Angular

Currently, I am in the process of developing a web application using Angular 7 for the frontend and NodeJS, MongoDB, and ExpressJS for the backend. The app functions as expected when I interact with it by navigating through, but there is an issue when manu ...

Conquer TypeScript type errors by utilizing Ramda's groupBy function

I've been facing a challenge with fixing this typescript error related to using ramda's groupBy function: 245: const groups = R.groupBy((row: Record) => { 246: return row[this.props.groupBy] 247: })(this.props.data) The def ...

Can someone guide me on finding my staticwebapp.config.json within Azure Devops for deploying Azure Static Web Apps during a release?

After setting up a pipeline to build the artifact for my Angular application, I encountered an issue with deployment where specific URLs would redirect me to a 404 error page. This problem seems to be related to the configuration in staticwebapp.config.jso ...

Angular 11 reactive form not reflecting real-time changes in input field

I'm currently working on an Angular project and I need to dynamically update a reactive form field with data retrieved from an API called getNextCode(). I have a function that calls the API service like this: ngOnInit(): void { this.NextCodeService.g ...