How can TypeScript and MobX work together using Set()?

I'm encountering errors while trying to implement Set() in my Grocery Shopping app using MobX with TypeScript. I have a simple setup with defined types in types.ts:

types.ts

export type Item = {
  name: string;
  instock: number;
  price: number;
};

export type Buyer = {
  cash: number;
  items: Array<Pick<Item, 'name'> & { quantity: number }>;
};

export type IStore = {
  items: Item[];
  buyer: Buyer;
};

store.ts

import { observable, action, set, computed, makeObservable } from 'mobx';

import type { Item, IStore, Buyer } from './types';

export class Store implements IStore {
  items: Item[] = [
    {
      name: "Egg",
      instock: 30,
      price: 4
    },
    {
      name: "Apple",
      instock: 24,
      price: 20
    },
    {
      name: "Banana",
      instock: 60,
      price: 8
    }
  ]

  buyer: Buyer = {
    cash: 50,
    items: [],
  }

  constructor() {
    makeObservable(this, {
      items: observable,
      buyer: observable,
      buyItem: action.bound,
    });
  }

  buyItem(name: string, price: number, quantity: number) {
    if (this.buyer.cash - price * quantity > 0) {
      this.buyer.items.push({ name, quantity })
      this.buyer.cash = this.buyer.cash - price * quantity
    }
  }
}

export const store = new Store();

I'm looking to use Set() for the buyer property in IStore. I want to change the type declaration in types.ts to utilize Set():

.
.
.
export type IStore = {
  .
  .
  .
  buyer: new Set<Buyer>();
};

Could someone shed light on this as the available docs lack a comprehensive example? How can I implement this change in store.ts as well?

For a working example, check out this Stackblitz Reproduction.

Answer №1

Instead of using Set, I opted for Map in my implementation. However, feel free to switch it to Set as it will work just as effectively.

I used Map with the method .has() to verify the uniqueness of the stored item names, giving it a functionality similar to a Set.

You can check out the Stackblitz project here → https://stackblitz.com/edit/react-mobx-grocery-shopping?file=index.tsx

types.ts

export type Product = {
  name: string;
  stock: number;
  cost: number;
};

export type CustomerProduct = Pick<Product, 'name'> & { quantity: number };

export type Customer = {
  money: number;
  products: Map<string, number>;
};

export type StoreInfo = {
  products: Product[];
  customer: Customer;
};

store.ts

import { observable, action, makeObservable } from 'mobx';

import type { Product, StoreInfo, CustomerProduct, Customer } from './types';

export class Shop implements StoreInfo {
  products: Product[] = [
    {
      name: "Milk",
      stock: 20,
      cost: 3
    },
    {
      name: "Bread",
      stock: 15,
      cost: 2
    },
    {
      name: "Cheese",
      stock: 25,
      cost: 5
    }
  ]

  customer: Customer = {
    money: 50,
    products: new Map<string, number>(),
  }

  constructor() {
    makeObservable(this, {
      products: observable,
      customer: observable,
      purchaseProduct: action.bound,
    });
  }

  purchaseProduct(name: string, cost: number, quantity: number) {
    if (this.customer.money - cost * quantity >= 0) {
      if (this.customer.products.has(name)) {
        const alreadyPurchased = this.customer.products.get(name)
        this.customer.products.set(name, quantity + alreadyPurchased)
      }
      else
        this.customer.products.set(name, quantity)
      this.customer.money = this.customer.money - cost * quantity
    }
  }
}

export const storeInfo = new Shop();

index.tsx

import React, { Component } from 'react';
import { render } from 'react-dom';
import { observer } from "mobx-react";

import { useStore } from "./context";

const Application = observer(() => {
  const { products, customer, purchaseProduct } = useStore()
  const customerProducts = Array.from(customer.products)
  
  return (
    <div>
      <h1>Supermarket Shopping</h1>
      <table style={{ width: 400, lineHeight: 2, border: "1px solid black", textAlign: "center" }}>
        <thead>
          <tr>
            <th>Product</th>
            <th>Price</th> 
            <th>Available Stock</th>
            <th>Buy Now</th>
          </tr>
        </thead>
        <tbody>
        {products.map(product => (
            <tr key={product.name}>
              <td>{product.name}</td>
              <td>${product.cost}</td>
              <td>{product.stock}</td>
              <td>
                <button onClick={() => {
                  purchaseProduct(product.name, product.cost, 1)
                }}>
                  Buy 1
                </button>
              </td>
            </tr>
          ))}
          </tbody>
      </table>
      <h2>${customer.money} left in wallet</h2>
      {customerProducts.length > 0 && (
        <>
          <h2>Purchased Items:</h2>
          <ul>
            {customerProducts.map(product => {
              return <li key={product[0]}>{product[1]} {product[0]}</li>
            })}
          </ul>
        </>
      )}
    </div>
  )
})

render(<Application />, document.getElementById('root'));

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

experiencing difficulties in retrieving the outcome from a sweetalert2 popup

function confirmation() { swal.fire({ title: "Are you absolutely certain?", text: "You are about to permanently delete important files", type: "warning", showCancelButton: true, show ...

Tips for accurately defining prop types in next.js when utilizing typescript?

Here is the content of my index.tsx file: import type { NextPage } from "next"; type AppProps = { articles: { userId: number; id: number; title: string; body: string; }; }; con ...

The issue of the selection option not being cleared after being set to 0 persists in JavaScript

I am facing an issue where I need to reset the select option to `0` when another option is selected. I have tried the code below for this purpose. if (varALPO1MobNum == "0") { var selectElement = $(&apo ...

Exploring the features of Vue.js with the code snippet 'ts 1109'

I need some assistance with my code as I seem to have one incorrect answer when using the if statement. The error code that I am encountering is ts1109 and I am not sure why VS Code is showing this. Thank you in advance for any help provided :) var calcu ...

What modifications need to be made to the MEAN app before it can be deployed on the server?

Following a tutorial on Coursetro, I was able to successfully build an Angular 4 MEAN stack application. However, when it comes to deploying the app on a server running on Debian-based OS, I am facing some challenges. The application should be accessible o ...

Netlify is unable to install a forked npm module due to the failure to retrieve metadata

I recently forked and modified the g-sheets-api module. Here is my version: https://github.com/lpares12/g-sheets-api After making the modifications, I installed it in my web project using the following command: npm install git+https://github.com/lpares12/ ...

The gltf model fails to load on Chrome for Android when using Threejs

I encountered an issue while attempting to showcase a basic GLTF 3d model on my website. Surprisingly, it functions smoothly on desktop Mac and Windows, as well as on iOS in Safari and Firefox. However, it fails to load on Android's Chrome browser. St ...

Issue when Updating Component State: React child cannot be an object

I'm currently in the process of familiarizing myself with React and how to manage component state. My goal is to build a component, set up the initial state using a constructor, make a GET request to the server to fetch an array of objects, and then ...

Guide to developing a private shared Node.js module using TypeScript

I have a unique idea for a nodejs server service, consisting of: a REST API, and various asynchronous workers. My vision is to separate these components into different subnets and git repositories while still enabling them to access the same database en ...

Angular multiple checkbox array iteration in ng-repeat

I am currently working on a form using Angular and facing a challenge with a specific section. Within the form, there is a 'Divisions' segment that includes a list of checkboxes generated dynamically from an API call. Users are required to selec ...

Utilizing JSONP callbacks in Dart

I've been struggling with implementing basic JSONP in Dart and I can't seem to figure it out. After reading this specific blog post along with another helpful resource, it suggests using window.on.message.add(dataReceived); to receive a MessageEv ...

Sending a div class as a parameter to a JavaScript function

Wondering if it's possible to pass a div's class into a JavaScript function. I'm using SquareSpace so adding an id to the div is not an option, but it works fine with divs that have ids. JQuery is already loaded. This is my current train of ...

React Native - Invariant Violation: Objects cannot be used as a React Child (Utilizing Node.js for the backend)

Trying to calculate the total sum of orders and their quantity using Node JS on the backend. However, encountering issues with the fetch functions not working properly or missing something unknown. The API works as expected when tested in Postman, but err ...

Equal-Height Slide Deck Holder

I'm struggling to maintain a consistent height of 700px for my image slideshow, which consists of four images with varying heights. I attempted setting the img at max-height: 700px, but unfortunately that didn't yield the desired outcome. You ca ...

What is the best way to organize the data retrieved from the api into a map?

In my search page component, I display the search results based on the user's query input. Here is the code snippet: "use client"; import { useSearchParams } from "next/navigation"; import useFetch from "../hooks/useFetch&qu ...

Change the image size as you scroll through the window

While my opacity style is triggered when the page is scrolled down, I am facing an issue with my transform scale not working as expected. Any suggestions on how to troubleshoot this or any missing pieces in my code? Codepen: https://codepen.io/anon/pen/wy ...

Mysterious data organization - transform into an object

As I interact with an API, there is a value that I cannot quite pinpoint. My goal is to transform this string into a JavaScript object, but the process seems complex and confusing. Does anyone have insight on what this data represents and how it can be co ...

using database URL as an AJAX parameter

I am currently working on a Python CherryPy controller that needs to validate a database URL by attempting a connection. However, I am facing challenges with passing the parameter to the method. Below is my AJAX call: $.ajax({ async: false, ty ...

Tips for retaining the value of a variable in JavaScript

I am a page that continuously redirects to itself, featuring next day and previous day arrows. Upon loading, the page always displays the new day. The days are stored in a localStorage as follows: for(var i = 0; i < status.length; i++) { local ...

html<script src="" and causing a redirect when button is clicked

My login.html page for logging in can be found in the design folder. <html> <head> <title>Login Page</title> <script src="../Script/login.js"> </script> </head> <body> <h3> Login</h3> ...