Ways to incorporate conditional checks prior to running class methods

Seeking input on handling async data retrieval elegantly.

When initializing a class with asynchronous data, I have been following this approach:

class SomeClass {
  // Disabling strictPropertyInitialization
  private someProperty: SomeType 

  public async init(): Promise<this> {
    this.someProperty = await goAndGetDataFromWhoKnowsWhere();
    return this;
  }

  public async aMethod(): Promise<AType> {
    // do something
  }

  public async anotherMethod(): Promise<AnotherType> {
    // do something
  }
}

Users (myself / co-worker) are expected to use the class like this:

const someResult = new SomeClass()
  .init()
  .then( thatClass => thatClass.aMethod() )

This method works fine, but there is no assurance that the init() will always be called. In case it gets missed, issues arise.

We could enable strictPropertyInitialization and add checks in every class method. While effective, repeating similar lines in each method suggests room for improvement.

class SomeClass {
  private someProperty: SomeType | undefined // For enforcing null-check

  public async init(): Promise<this> {
    this.someProperty = await goAndGetDataFromWhoKnowsWhere();
    return this;
  }

  public async aMethod(): Promise<AType> {
    if (!this.someProperty) await this.init();
    // do something
  }

  public async anotherMethod(): Promise<AnotherType> {
    if (!this.someProperty) await this.init();
    // do something
  }
}

Are there any solutions or design patterns to address this issue? Appreciate any help! :)

Answer №1

Instead of exposing the new() constructor call, have you considered making the constructor private and creating a static method init() that asynchronously constructs an instance while populating it with data:

class SomeClass {

  static async init(): Promise<SomeClass> {
    return new SomeClass(await goAndGetDataFromWhoKnowsWhere());
  }

  private constructor(private someProperty: SomeType) {  }

  // your other methods    
}


new SomeClass("oops"); // unable to do this

SomeClass.init().then(thatClass => thatClass.aMethod());

This approach makes it extremely difficult for users to misuse the code. I hope this suggestion sparks some ideas for you. Best of luck!

Answer №2

One alternative is to encapsulate the creation of the class within a function. If each instance requires the init method to be invoked, you can simply handle it during instantiation:

(I apologize for not using TypeScript; it's just not my area of expertise.)

const fetchData = async () => 123;

const MyClass = () => {
  class MyClass {
    async init() {
      this.data = await fetchData();
      return this;
    }
  }
  return new MyClass().init();
};

MyClass().then(obj => {
  console.log('data:', obj.data);
});

As noted in jcalz's answer, this approach does not support the use of the new keyword:

new MyClass(); // TypeError: MyClass is not a constructor

Answer №3

Instead of going through all that trouble, why not simply utilize a function?

function CustomFunction(){
  var freshObject = Object.create(/* insert your prototype here */)
  return fetchInformationFromUnknownSource()
  .then((data) => {
    freshObject.someAttribute = data;
    return freshObject;
  })
}

CustomFunction().then((freshObject) => {})

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

Styling components using classes in Material-UI

I recently started using material-ui and noticed that it applies inline styles to each component. After running a test with multiple instances of the same component, I realized that there was no CSS-based styling - only repeated inline styles were generate ...

Numerous HTML documents being uploaded to the server for a multitude of individuals

Currently, I am developing a game on a website where players create new rooms and are assigned specific roles with individual powers. Some players need to wait for input from others, creating a dynamic gameplay experience. Additionally, there are certain ...

Perl's powerful capabilities allow for the creation of interactive drop-down menus

As a newcomer to web programming, I have recently been tasked with scripting projects during my summer internship. I've been utilizing Perl to develop CGI scripts for my company's internal website, specifically catering to the needs of the develo ...

Using an arbitrary object as an argument in a CoffeeScript anonymous function

When I execute the below Coffeescript code: @total = (a, b) -> a + b The resulting compiled Javascript is: (function() { this.total = function(a, b) { return a + b; }; }).call(this); Is there a method in Coffeescript to substitute ...

Navigating through elements in the hidden shadow DOM

Can elements within the Shadow DOM be accessed using python-selenium? For example: There is an input field with type="date": <input type="date" name="bday"> I want to click on the date picker button located on the right and select a ...

Looking to subtly transition from the current webpage to the next one with a fading effect?

I'm looking to create a smooth transition between web pages on my site by slowly fading out the current page and fading in the next one when a link is clicked. $(document).ready(function() { $('body').css("display","none"); $(&a ...

Dynamically Growing Navigation Bar Elements with Nested Subcategories Based on Class Identification

Let's say you have a menu bar structured as follows: <nav> <ul class="nav"> <li class="menu1"><a href="#">Menu Item 1</a></li> <li class="menu2"><a href="#">Menu Item 2</a> <ul& ...

The combination of Three.js and React

Hello everyone! I am completely new to Three.js and I'm currently attempting to integrate it with React. While looking for resources, I came across this helpful medium article on the topic: Starting with React 16 and Three.js in 5 minutes My goal is ...

Explaining the structure of a nested object within a TypeScript declaration file

As I work on my project, I encounter the challenge of importing an object created by a dynamic function. The dynamic nature of the keys on this object poses a problem for the IDE, as it cannot determine what keys are present based on the provided config. T ...

Positioning Div at the Bottom of a Interactive Flip Card Using Bootstrap 4

My current project features a creative flip image card created using bootstrap and js. On the back of the card, there is a title, a main text body, and a few small additional pieces of information. My goal is to have these three small bits of information a ...

What is the best approach to dynamically enable or disable a button depending on the state of multiple checkboxes in React.js?

Incorporated within a page is a component responsible for displaying multiple checkboxes and toggles. Located at the bottom of this component is a button labeled confirm, designed to save modifications and initiate a backend update request. A new functio ...

Error: The lockfile and package.json file are not synchronized when running npm

Having a problem with NPM where the package-lock and package.json files are out of sync. Tried deleting node_modules, running npm install, but issue persists. Any suggestions? Error: npm ci can only install packages when package.json and package-lock.json ...

Executing a php function upon onchange event triggered by CKEditor

My task involves invoking a PHP function when I suspect it is being triggered by an ajax call. Utilizing ckeditor, I aim to detect any keyboard activity and believe that using onchange will serve this purpose. Subsequently, I plan to execute a function t ...

The npm postinstall script is functional, however, it does not complete successfully and ends

I have encountered an issue while trying to solve a problem with my project. In my package.json file, I have included a postinstall script that connects to a database and calls a function to write data into it. The script seems to be working fine as the da ...

Activate a Dropdown Menu by Clicking in a React Application

I have a collapsible feature where you can click to expand or collapse a dropdown. Currently, the dropdown can only be clicked on where the radio button is located. I want the entire area to be clickable so that users can choose the dropdown by clicking an ...

Error: Query has already been processed: Updating Todo with ID "612df063a8f"

After updating mongoose to the latest version (6.0.2), I encountered an error that crashes the application whenever .updateOne() is executed. However, the object is still updated inside the database. Below is my code snippet: async(req,res) => { a ...

Unable to load the threejs module

I am still learning about threejs and have mostly worked on projects using a dev server (vite) locally. This setup limited me to accessing my projects only from the browser on my computer. Here is how I typically include my files in these projects: <bod ...

Issue with the positioning of the datepicker is not functioning properly

I'm currently facing an issue with the position of a date picker plugin from jquery. The search box on my website allows users to select a range of dates using the date picker, but when enabled, the date picker appears at the bottom left corner of the ...

IE Troubles: Timer Function Fails in Asp.Net MVC

I implemented the following code snippet: @Using Ajax.BeginForm("Index", New AjaxOptions() With { _ .UpdateTargetId = "AnswerSN", .HttpMethod = ...

hierarchical browsing system

Take a look at the image provided below. Currently, I am using multiple unordered lists - specifically 5. However, I would prefer to consolidate them all into a single nested ul. I am encountering two issues: How can I add a border-bottom to the hori ...