Sending arrays as parameters to a TypeScript constructor

Recently, I delved into creating an Idle Game in TypeScript (similar to cookie clicker, but not quite as refined yet!). My knowledge of TypeScript and JavaScript is still at a beginner level.

The challenge arose when I decided to switch the "cost" attribute from a simple number to a more complex type called "Cost". The intention behind this change was to accommodate future objects (like the winged rat) that would require multiple resources, not just scrap. I have a feeling that my implementation of Cost might be flawed somewhere, or there could be issues with the constructor's setup, or it's not being instantiated correctly.

Currently, the problem arises when I try to access "resourceList["rat"].cost.costList["scrap"]", as it returns undefined. This issue results in the "rat" button remaining disabled indefinitely.

class Resource {
    name: string;
    amount : number;
    cost: Cost;
    value: number;
    display() : string
    {
        if(this.amount - Math.floor(this.amount) > 0)
        {
            return this.amount.toFixed(2);
        }
        else
            return this.amount.toString();
    }
}

class Cost {
    costList: { [id: string] : number; } = {};
    constructor(res:string[], cost:number[]){
        var i = 0;
        for(var r in res)
        {
            var c = cost[i];
            this.costList[r] = c;
            i++;
        }
        return this;
    }
}

class Scrap extends Resource {
    constructor(public amount) {
        super();
        this.name = "scrap";
        this.cost = new Cost([""],[0]);
        document.getElementById('scrapLbl').innerHTML = this.name + ": ";
    }
}

class Rat extends Resource {
    constructor(public amount) {
        super();
        this.name = "rat";
        this.cost = new Cost(["scrap"],[10]);
        this.value = 1;
        document.getElementById('ratLbl').innerHTML = this.name + ": ";
    }
}

class wRat extends Resource {
    constructor(public amount) {
        super();
        this.name = "wrat";
        this.cost = new Cost(["scrap", "rat"],[10, 1]);
        this.value = 1;
        document.getElementById('wratLbl').innerHTML = this.name + ": ";
    }
}

var resourceList: { [id: string] : Resource; } = {};
var curScrap = new Scrap(0);
var curRat = new Rat(0);
var curWRat = new wRat(0);
resourceList["scrap"] = curScrap;
resourceList["rat"] = curRat;
resourceList["wrat"] = curWRat;

function updateView()
{
    document.getElementById('scrapId').innerHTML = resourceList["scrap"].display();
    document.getElementById('ratId').innerHTML = resourceList["rat"].display();
    if(resourceList["scrap"].amount >= resourceList["rat"].cost.costList["scrap"])
    {
        document.getElementById('scrapRat').disabled = false;
    }
    else
    {
        document.getElementById('scrapRat').disabled = true;
    }
    document.getElementById('ratId').title = resourceList["rat"].cost.toString();
}

function updateValues()
{
    if(resourceList["rat"].amount > 0)
        resourceList["scrap"].amount += (resourceList["rat"].value * resourceList["rat"].amount)/10;
}

function collectScrap()
{
    resourceList["scrap"].amount += 1;
}

function scrapRat()
{
    //cost
    resourceList["scrap"].amount -= resourceList["rat"].cost.costList["scrap"];
    //create
    resourceList["rat"].amount += 1;
    //update cost
    resourceList["rat"].cost.costList["scrap"] *= 1.12;
}

window.setInterval(function(){
    this.updateValues();
    updateView();
}, 100);

I'm uncertain if the HTML is required, but here it is:

<!DOCTYPE HTML>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Scrap Clicker</title>
    <link rel="stylesheet" href="css/bootstrap.min.css" media="screen">
    <script src="js/jquery-2.2.1.min.js"></script>
    <script src="js/bootstrap.min.js"></script>
</head>
<body>

<label id="scrapLbl" ></label> <span id="scrapId">0</span>
<label id="ratLbl" ></label> <span id="ratId">0</span>
<label id="wratLbl" ></label> <span id="wratId">0</span>
<div>
    <button title="Free" data-toggle="popover" data-trigger="hover" data-content="Dig!" class="btn btn-lg btn-primary" onclick="collectScrap()">collect scrap</button>
    <button title="10 Scrap" data-toggle="popover" data-trigger="hover" data-content="Strap some scrap to a rat, now you've got a Scrap-Rat!" class="btn btn-lg btn-primary" onclick="scrapRat()" id="scrapRat" disabled>scrap rat</button>
    <button title="10 Scrap, 1 rat" data-toggle="popover" data-trigger="hover" data-content="Strap some scrap to a Scrap-Rat, now you've got a Flying-Scrap-Rat!" class="btn btn-lg btn-primary" onclick="wRat()" id="wRat" disabled>Winged scrap rat</button>

</div>
<script src="game.js"></script>
<script>
    $(document).ready(function(){
        $('[data-toggle="popover"]').popover();
    });
</script>
</body>
</html>

Bonus Points: Present me with an improved method to manage resources and costs efficiently!

Answer №1

The issue lies not in the typescript code, but rather in your implementation of the for..in loop:

let items = ["x", "y", "z"]
for (var element in items) {
    console.log(element);
}
// x,y,z

When using a for...in loop with an array, it's more appropriate to use "element" as opposed to "item". Consider updating your Price class as follows:

class Price {
    priceList: { [id: string] : number; } = {};
    constructor(prods:string[], price:number[]){

        for (let j = 0; j < prods.length; j++) {
            this.priceList[prods[j]] = price[j];
        }
    }
}

EDIT: To address your extra points, a more type-safe approach to defining Price is by utilizing an interface:

interface Price {
    [key: string]: number;
}

class Product {
    price: Price;
    //...
}

class Cat extends Product {
    constructor(public cost) {
        super();
        this.price = <Price>{
            "dollars": 100
        };
    }
}

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

React Router v6 is throwing an error stating that within the <Routes> component, all children must be either a <Route> or <React.Fragment>

While the code snippet below may have worked perfectly fine in React Router v5, it's causing an error in React Router v6. Error: [Player] is not a <Route> component. All component children of <Routes> must be a <Route> or <React ...

Sending multiple arguments to a Vuex action

In the Vue Component code snippet below, I have a method: loadMaintenances (query = {}) { this.getContractorMaintenances(this.urlWithPage, query).then((response) => { this.lastPage = response.data.meta.last_page }) } I am trying to pass the par ...

Creating a structured file hierarchy by extracting files from Amazon S3 and transferring them for storage in Firebase

I am looking to retrieve key/value pairs from Amazon S3 and then store some of the obtained information in Firebase to build a file system in AngularJS. This question focuses only on storing in Firebase. It is essential to be able to create an unlimited ...

Determine the number of duplicate items in an array of objects using JavaScript and save the count as a separate object

I have a collection of objects in JavaScript representing products. These products are shown in a list similar to a shopping cart. The goal is to identify and count duplicate products in the array based on their _id value. Once duplicates are found, they ...

How can you connect a jQuery UI sortable component to an array?

Is there a way to connect a jQuery UI sortable element with an array in order to assign an index to each sortable element within the array? I am looking for a method to automatically sort the array based on the movement of the sortable elements. Any sugg ...

Using the Angular translate filter within a ternary operator

I am currently working on translating my project into a different language. To do this, I have implemented the Angular Translate library and uploaded an external JSON file containing all the translations. Here is an example of how it looks: { "hello_wor ...

Opting for pre-selected default data within Material UI's select component

When utilizing the select component in Material UI, I am tasked with passing data as props to set a default selected value. The parent component provides the coursename prop, which can be accessed through this.props.coursename. I want this passed course to ...

Using Angular's dependency injection in a project that has been transpiled with Babel

I am currently attempting to transpile my Angular 6 project, which is written in TypeScript, using the new Babel 7. However, I am facing challenges with getting dependency injection to function properly. Every time I try to launch the project in Chrome, I ...

Guide on retrieving JSON information through an AJAX request within an AngularJS Bootstrap modal

I am eager to implement the following functionality: a button that triggers a dialog/modal from Angular Bootstrap which showcases a loading indicator as the application retrieves JSON data from the server. Once the data is fetched, it should be displayed w ...

Tips for accessing nested values post-subscription in Angular with JSON data?

I have implemented a getReports method that utilizes my web API's get method to retrieve JSON formatted responses. Step1 getReports() { return this._http.get(this.url) .map((response: Response) => response.json()) ...

"Unindexing data in Angular: A step-by-step guide

Can someone help me figure out how to delete an item by index in Angular? I have a parameter and a remove button, but when I tried putting my parameter inside the remove button it didn't work. How can I fix this? deleteRowFiles(rowIndex: number){ th ...

Create an array containing key-value pairs where the values are objects

I've been struggling to create a specific data structure in Javascript and I could really use some guidance: [arrayValue: {objectKey: objectValue}, arrayValue2: {objectKey: objectValue}] Here's what I've attempted so far: var arr = []; var ...

offsetWidth varies across different browsers

There seems to be a 1px difference in the value of element.offsetWidth between Firefox and Chrome. I have been researching this issue. I attempted to apply a CSS reset and moved the element further away from the screen borders (as older versions of IE wer ...

Using nodeJS's util module to format and pass an array

I've been using util.format to format strings like this: util.format('My name is %s %s', ['John', 'Smith']); However, the second parameter being an array ['John', 'Smith'] is causing issues because m ...

Guide on assigning a callback function in JavaScript

In this code snippet, I am initializing a new object variable and passing an object as an argument: const newObj = new customObject({ first : $('#fname').val(), last : $('#lname').val(), fn : function() { alert(this ...

Add information to the Database seamlessly without the need to refresh the page using PHP in combination with JQuery

Check out my code below: <form action='insert.php' method='post' id='myform'> <input type='hidden' name='tmdb_id'/> <button id='insert'>Insert</button> <p i ...

What is the best way to display a list of search outcomes?

I've hit a roadblock trying to figure out what's happening. Despite watching videos on maps, arrow functions, and implicit returns, my code still doesn't seem to make sense. Everything checks out when I console log it, all the data is there. ...

Tips for ensuring an animation is triggered only after Angular has fully initialized

Within this demonstration, the use of the dashOffset property initiates the animation for the dash-offset. For instance, upon entering a new percentage in the input field, the animation is activated. The code responsible for updating the dashOffset state ...

The instance is referencing a property or method (...) that has not been defined, resulting in an error during rendering

"Unrecognized property or method "show" is being referenced in the rendering stage. To resolve this, ensure that the property is reactive by including it in the data option for functional components or initializing it for class-based components." This blo ...

Convert all existing objects to strings

I have a type that consists of properties with different data types type ExampleType = { one: string two: boolean three: 'A' | 'Union' } Is there an easier way to define the same type but with all properties as strings? type Exam ...