Ensuring the longevity of a generator function instance throughout various subclasses

I am in need of a solution for ensuring that each instance of my ROOT NODE class always has an ID of 0 upon instantiation.

Furthermore, I want to assign integer IDs sequentially to each child object created from this ROOT NODE. For example, the first child should have an ID of 1, the second child should have an ID of 2, and so on. It's important to note that the child nodes are subclasses of the ROOT NODE.

In my initial implementation, I utilized a generator function that the ROOT NODE referenced for its ID, and then the CHILD NODES accessed the ROOT NODE to obtain their respective IDs. This approach worked as intended:

const skillIdGenerator = (function* () {
  let id = 0;
  while (true) {
    yield id;
    id++;
  }
})();

class RootNode {
  private id: number;
  private children: Map<number, Skill>;

  constructor() {
    this.id = skillIdGenerator.next().value;
    this.children = new Map();
  }

  getId(): number {
    return this.id;
  }
}

class Node extends RootNode {
  private parents: Map<number, RootSkill | Skill>;

  constructor(parentSkills: (RootSkill | Skill)[], name: string) {
    super();
    this.parents = new Map(parentSkills.map((p) => [p.getId(), p]));
  }
}

However, this setup does not handle scenarios where there are multiple trees with multiple ROOT NODEs.

I am seeking advice on the most effective way to maintain a generator for all children under each ROOT NODE, while also creating a new generator for each fresh ROOT NODE instantiation.


I experimented with relocating the skillIdGenerator inside the ROOT NODE class using two different approaches: one as a function returning the next ID, and another as an iterable generator. Unfortunately, both attempts proved unsuccessful.

Answer №1

Upon careful examination, it seems that the designated hierarchy for constructing a tree is flawed. The distinction between a root node and any other node appears to be arbitrary. In essence, every sub-tree within a tree can still be considered a tree on its own. Thus, differentiating between a RootNode and a regular Node seems illogical. Instead, I propose combining these two classes into one:

const skillIdGenerator = function* () {
  let id = 0;
  while (true) {
    yield id;
    id++;
  }
};

class TreeNode {
  private id: number;
  private children: Map<number, TreeNode> = new Map();

  private constructor(private idGenerator: Generator<number>, private parents: Map<number, TreeNode> | null = null) {
    this.parents  = parents;
    this.id = this.idGenerator.next().value;
  }

  getId(): number {
    return this.id;
  }

  getChildren(): ReadonlyMap<number, TreeNode> {
    return this.children;
  }

  getParents(): ReadonlyMap<number, TreeNode> {
    return this.parents ?? new Map();
  }

  get isRoot() {
    return this.parents === null;
  }

  static createRootNode() {
    const node = new TreeNode(skillIdGenerator());
    return node;
  }

  createNode() {
    const newParents = new Map(this.parents ?? [])
      .set(this.getId(), this);

    const node =  new TreeNode(this.idGenerator, newParents);
    this.children.set(node.getId(), node);
    return node;
  }
}

Playground Link with demo usage

The key adjustment lies in limiting the construction process solely to factory methods:

  • createRootNode() - This static method ensures that each call initiates a new tree. A fresh generator is initialized as part of the instantiation and then passed to the constructor to derive the ID.
  • createNode() - As an instance method, it is only applicable within an existing tree. By passing the current generator through the constructor, the ID is obtained from the next value in the sequence.

This approach results in all nodes referencing the same generator object. While somewhat redundant, it offers a bit of convenience during node creation.

Demo usage for generating:

    0
  / | \
 1  2  3
 |    / \
 4   5   6
     |
     7
const root = TreeNode.createRootNode();

const left  = root.createNode();
const mid   = root.createNode();
const right = root.createNode();

const leftMid = left.createNode();

const rightLeft  = right.createNode();
const rightRight = right.createNode();

rightLeft.createNode();

Answer №2

Revise your code to transform skillIdGenerator from an Immediately Invoked Function Expression (IIFE) into a generator function. By making this change, you will be defining the function without immediately executing it as a Generator object. This allows for the creation of a new instance of the Generator object for each RootNode:

const skillIdGenerator = function* () {
  let id = 0;
  while (true) {
    yield id;
    id++;
  }
};

class RootNode {
  private id: number;
  private children: Map<number, Skill>;
  private skillId = skillIdGenerator();

  constructor() {
    this.id = skillId.next().value;
    this.children = new Map();
  }

  getId(): number {
    return this.id;
  }
}

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

Is it possible to loop through a subset of a collection using *ngFor?

Is it possible to iterate through a specific range of elements in a collection using *ngFor? For instance, I have a group of checkboxes with their form control name and label specified as follows: [{id: 'c1', label: 'C1'}, ...] Assum ...

Encountering Error TS2411 when upgrading from Typescript version 1.0.0 to 1.1.0-1

After updating my TypeScript using npm install typescript -g, I have been encountering a recurring error during compilation. Although the compilation is successful, it's becoming tedious. cmd.exe /D /C C:/Users/Vado/AppData/Roaming/npm/tsc.cmd --sour ...

What is the reason for the prohibition of bitwise operators in tslint?

While we're unable to utilize bitwise operators in templates, what is the rationale behind tslint prohibiting their use within TypeScript code? "no-bitwise": true, ...

Tips for resolving Circular dependency issue in node.js?

While working on a post request, I encountered an issue with the code below: try{ const _id = await db.collection('UserInformation').insertOne(userObj); await db.collection('LoggedInUser').updateOne({ userId: _id }, { '$set&ap ...

Exploring Typescript: Understanding the nuances of importing and exporting values or references

Currently, I am facing a challenge while converting Javascript code to Typescript, specifically with regards to import and export functionality: Intended Functionality: I aim to import 'POST_Requirements' into multiple other files. Each file tha ...

Searching for all unconverted strings in a Vuejs project can be achieved by following these steps

I have recently found myself delving into a Vue.js and Typescript project with legacy code. The project utilizes the vue-i18n library for handling translations, using this.$t in every component to access translations stored in directories like translations ...

Node.js server side rendering encounters import file failure

In my current project, I am working on implementing server side rendering with React using TypeScript. All of the components, containers, and other directories are located within the src directory. When React imports a file from a location such as ./src/p ...

Having trouble displaying the week number in Angular Highcharts?

I am currently facing an issue with implementing highcharts in my Angular application that I am unable to resolve. My goal is to display the week number on the xAxis using the 'datetime' type. I came across this JSFiddle that seems to provide a ...

Creating reducers for a unique data type: A step-by-step guide

Today, I was working on enhancing a shopping website using React Typescript and Context API. My goal is to utilize React Reducers to manage the state of my Shopping Cart. I have custom Types defined for the Product type, which includes an Items Array and s ...

Strange Behavior of ngIf and @Input in Angular 2

Despite console indicating false, NgIf appears to always evaluate as true. The issue stems from the component's HTML below: <product-component-tree itemSku="{{item.itemSku}}" selectable="false" classes="col-md-12 col-xs-12"></product-compo ...

Guide on verifying API response structure in Playwright with TypeScript

As a newcomer to Playwright, my focus is on writing API tests in TypeScript with an API response structured like this: { "id" : "abc123", "appCode" : "09000007", "applicationReference" : "ABCDEF& ...

Tips for triggering functions when a user closes the browser or tab in Angular 9

I've exhausted all my research efforts in trying to find a solution that actually works. The problem I am facing is getting two methods from two different services to run when the browser or tab is closed. I attempted using the fetch API, which worke ...

Is there a way to utilize Typescript enum types for conditional type checking?

I'm working with restful services that accept enum values as either numbers or strings, but always return the values as numbers. Is there a way to handle this in TypeScript? Here's my attempt at it, although it's not syntactically correct: ...

failure to render updated content after modification of variable

I am facing an issue with triggering a function in the component: componentA.ts html = 'hey'; this.onElementSelected(r => this.change()); public change() { console.log(this.html); if (this.html === 'hey&ap ...

Error encountered when providing valid data types as arguments in a React/Typescript function

I am facing an issue when passing a string variable to a function. To address this, I have created an interface called MyMessageProps where I declare the message as a string. Subsequently, the function MyMessage utilizes this interface to return with the ...

Developing a continuous running test loop

Currently, I have a code that runs fine, but I am looking to modify it to run in a loop that counts the number of elements with the class="socal" and tests each link. module.exports = { 'Unitel Fitness - click' : function (browser) { bro ...

Have you ever wondered why querySelectorAll('div') gives back a list of HTMLDivElement elements, while querySelectorAll('div.className') provides a list of Element elements in TypeScript?

I've been pondering why, when a class name is added to querySelectorAll, the type no longer shows up as HTMLDivElement. document.querySelectorAll('div').forEach(item => { // item type is HTMLDivElement }); document.querySelectorAll(& ...

Verifying user privilege within settings database (written in Typescript for Aurelia framework)

Working on navigation with authorization. This is a snippet of my code: run(navigationInstruction: NavigationInstruction, next: Next) : Promise<any> { let requiredRoles = navigationInstruction.getAllInstructions() .map(i ...

Utilizing Angular Components Across Various Layers: A Guide

Consider the following component structure: app1 -- app1.component.html -- app1.component.ts parent1 parent2 app2 -- app2.component.html -- app2.component.ts Is it possible to efficiently reuse the app2 component within the ap ...

Transforming the window property in distinct entry points for TypeScript

During the initial page load, I am looking to transfer data from a template to a TypeScript file by attaching it to the window object. I want each page to utilize the same variable name for its specific data (window.data). An example of this can be seen in ...