Typescript on the client-side: what is the best way to eliminate circular dependencies when using the factory method design pattern?

In my code, I have implemented the factory method pattern. However, some instances using this pattern end up with circular dependencies. Removing these dependencies has proven to be a challenge for me. To illustrate, consider the following example:

// factoryMethod.ts
import Instance1 from './Instance1';
import Instance2 from './Instance2';
import Instance3 from './Instance3';
import { Instance, InstanceName } from './Instance';

export const getInstanceByName = (
  instanceName: InstanceName
): Instance => {
  switch (instanceName) {
    case 'Instance1':
      return Instance1;
    case 'Instance2':
      return Instance2;
    case 'Instance3':
      return Instance3;
    default:
      throw new Error();
  }
};

// extremelyHelpfulUtilityFunction.ts
import { getInstanceByName } from './factoryMethod';

export const extremelyHelpfulUtilityFunction = (instanceName: InstanceName): number => {
  // An illustrative utility function
  return getInstanceByName(instanceName).num
}

// Instance.ts
export interface Instance {
  doSomething: () => number;
  num: number;
}

export type InstanceName = 'Instance1' | 'Instance2' | 'Instance3';

// Instance1.ts
import { extremelyHelpfulUtilityFunction } from './extremelyHelpfulUtilityFunction';

const i: Instance = {
  doSomething: (): number => {
    return extremelyHelpfulUtilityFunction('Instance2') + extremelyHelpfulUtilityFunction('Instance3'); // circular dependency
  },
}
export default i;

// Other instances defined below, you get the idea.

As I compile this code using rollup, it raises a warning about the circular dependencies present. Although the code functions correctly, I am determined to eliminate this warning. How can I refactor the code so that InstanceX can access InstanceY without creating a circular dependency?

Answer №1

It seems that the main issue lies within the extremelyHelpfulUtilityFunction needing to be aware of getInstanceByName. I suggest a different approach where the factory method's result is predetermined by the caller and passed as an argument to the utility function.

Here is my proposal:

// InstanceA.ts
const instanceA: Instance = {
  doSomething: (): number => {
    return (new InstanceB()).toNumeric() + (new InstanceC()).toNumeric()
  },
}

The function toNumeric should be defined in Instance.ts and customized in its subclasses, utilizing the utility function with appropriate arguments. For example:

// InstanceB.ts
const instanceB: Instance = {
  doSomething: ...,
  toNumeric: (): number => {
    return extremelyHelpfulUtilityFunction(5678)
  }
}

If you were to create a proper class for InstanceB instead of using an object, the code would look like this:

// InstanceB.ts
class InstanceB extends Instance {
  num = 5678;
  doSomething: ...
  toNumeric(): number {
    return extremelyHelpfulUtilityFunction(this.num)
  }
}
export default new InstanceB();

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

Stop the form from being submitted using ajax if there are no values in the form fields

Having issues with a basic form. Struggling to prevent submission when fields are empty. Is there a straightforward way to validate the fields and stop the form from submitting? Below is the HTML form: <form method="post" name="simpleForm" id="simpleF ...

Harnessing the Power of JSON Data Extraction with JavaScript

I stored the data in JSON format using the setItem method: localStorage.setItem('orderproduct', JSON.stringify([{imageSource: productImg, productTitle: title, productQuantity: qty, productPrice: finalprice}])); When I inspect it, this is how it ...

The second div element remains unselected in jQuery

Below is the example of an HTML structure: <span id="17">yes here</span> <div class="PricevariantModification vm-nodisplay"></div> <div class="PricesalesPrice vm-display vm-price-value"> <span class="a"></span> ...

How can I adjust the vertical position of Material-UI Popper element using the popper.js library?

https://i.stack.imgur.com/ZUYa4.png Utilizing a material-ui (v 4.9.5) Popper for a pop-out menu similar to the one shown above has been my recent project. The anchorElement is set as the chosen ListItem on the left side. My goal is to have the Popper alig ...

Using jQuery to restrict users from entering a character consecutively more than three times within a single word

Is there a way to restrict users from repeating the same character more than three times in a single word? For example, allowing "hiii" but not "hiiii" to be typed in a textbox? I am looking for something similar to how the textbox works on this website f ...

How much will it set me back for '`$(this)`?

Many individuals in this community frequently recommend caching the jQuery object generated from a DOM element, as illustrated by the following code snippet: $('#container input').each(function() { $(this).addClass('fooClass'); ...

Adjusting the height of a GAS iframe in WordPress with iframe-resizer: A step-by-step guide

I would like to embed an iframe of my Google Application Script Web into my WordPress site without the scroll bar. Refer to the image below for context. https://i.stack.imgur.com/7L6Tw.png I encountered an error message while attempting to use the iframe ...

The options in the dropdown menu vanish when interacting with a jQuery feature that relies on

Recently, I have found AJAX, JSON, and jQuery to be indispensable tools in my coding endeavors. The application I am working on is a replacement for a flawed one, and it is coming along nicely. Despite making progress with the AJAX method, I have encounte ...

From Vanilla Javascript to ES6 Spread Operator

I recently incorporated a script into my project that utilizes the ES6 spread operator to extract parameters from the URL. However, I encountered an issue when I realized that the project does not support ES6 syntax. While it is straightforward to apply t ...

Organizing a Collection of Likes within an AngularJS Service

I have a like button on my profile page that, when clicked, should add the user's like to an array and store it in the database. Within my profile controller, I have the following code: $scope.likeProfile = UserService.likeProfile(loggedInUser,$stat ...

Obtain the content enclosed by HTML tags

Looking to extract text between html tags? Imagine having a list of cities in California, each within paragraph tags. Can you retrieve only the text inside the paragraph tags? <div class="cities"> <div><p>Los Angeles</p><h5 ...

What is the definition of a type that has the potential to encompass any subtree within an object through recursive processes?

Consider the data structure below: const data = { animilia: { chordata: { mammalia: { carnivora: { canidae: { canis: 'lupus', vulpes: 'vulpe' } } } } }, ...

What is the reason behind being able to assign unidentified properties to a literal object in TypeScript?

type ExpectedType = Array<{ name: number, gender?: string }> function go1(p: ExpectedType) { } function f() { const a = [{name: 1, age: 2}] go1(a) // no error shown go1([{name: 1, age: 2}]) // error displayed ...

Encountered a problem initializing Rangy.js on Internet Explorer

Currently, I am developing an angular application that utilizes textAngular along with rangy-core and rangy-selectionsaverestore. However, I am encountering some errors specifically on the latest version of Internet Explorer: Module 'WrappedSelection ...

Retrieving AJAX data in a Node.js environment

In my HTML application, I am utilizing AJAX to showcase the output on the same page after the submit button is clicked. Before submitting, I am able to retrieve the values passed in the HTML form using: app.use(express.bodyParser()); var reqBody = r ...

Updating data from an API within a div using AJAX calls in a React application

I have designed a React template to showcase live football scores in the following manner: const LiveScore = () => { const {direction} = useThemeProvider(); const [selectedDay, setSelectedDay] = useState(parseInt(dayjs().format('DD'))); retur ...

The request.body in Express.js is currently undefined

const express = require('express'); const cors = require('cors'); const app = express(); app.use(express.json()) app.use(cors()); app.post('/', (req,res) => { console.log(req.body); res.send('received') ...

Tips on displaying substitute text in Angular when an Iframe fails to load the content located at the src

Currently, I am working on an Angular 12 application and have a requirement to fetch content from an external site and display it within a modal popup. To achieve this, I am using the <iframe src="url"> tag to retrieve the content from a se ...

Managing database downtime with TypeORM

In the event that my MSSQL server experiences a crash and an app client makes a request to the API, the current behavior is for it to endlessly spin until Express times out the unanswered request. By enabling logging in TypeORM, I am able to observe the e ...

Error 2322: Troubleshooting Typescript arrow functions overloads issues

Everything seems to be working well with the code below, except for an error that occurs with the resolve constant. const resolve: Resolve Type '(param: "case 1" | "case 2" | "case 3") => boolean | "string" | ...