Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

259
Views
Singleton config - how to avoid returning a Promise in typescript

I have my Configuration class:

interface ConfigObject {
  apiUrl: string;
  identityPoolId: string;
  identityPoolRegion: string;
  region: string;
  userPoolId: string;
  userPoolWebClientId: string;
}

class Configuration {
  private static _instance: ConfigObject;

  public static get Instance() {
    return (
      this._instance ||
      this.getConfig<ConfigObject>().then((config) => {
        this._instance = config;
        return config;
      })
    );
  }

  private static async getConfig<TConfig>(): Promise<TConfig> {
    const response = await fetch('env.json', {
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
      },
    });
    if (!response.ok) {
      throw new Error(response.statusText);
    }
    const data = await response.json();
    return data;
  }
}

export default Configuration.Instance;

and I want to access it's values in my service:

export default class APIService {
  static baseURL: string = `${Config.apiUrl}/mocked`;

Yet at the time of accessing Config.apiUrl is undefined

How can I make sure that the getConfig fetch gets executed and the actual object is returned instead?

about 4 years ago · Juan Pablo Isaza
1 answers
Answer question

0

You can't make an asynchronous process synchronous. But you can make your module wait to load until you've read that JSON file, by using top-level await, which is now broadly supported in browsers and by bundlers.

async function getConfigData(): Promise<ConfigObject> {
    const response = await fetch('env.json', {
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
      },
    });
    if (!response.ok) {
      throw new Error(response.statusText);
    }
    const data: ConfigObject = await response.json();
    return data;
}
const data = await getConfigData(); // *** Module load waits here

class Configuration {
    private static _instance: ConfigObject;

    public static get Instance() {
        if (!this._instance) {
            this._instance = data;
        }
        return this._instance;
    }
}

export default Configuration.Instance;

That said, there doesn't seem to be any purpose to the Configuration class, just export the data directly:

async function getConfigData(): Promise<ConfigObject> {
    const response = await fetch('env.json', {
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
      },
    });
    if (!response.ok) {
      throw new Error(response.statusText);
    }
    const data = await response.json();
    return data;
}
const data: ConfigObject = await getConfigData(); // *** Module load waits here

export default data;

Side note: Since objects are mutable by default, any module that imports the configuration data can modify it (for instance, if there's a data.example property, by doing data.example = "some value"). Maybe you want it to be mutable, in which case don't do anything, but if you don't you might use Object.freeze to make everything about the object read-only:

// ...
const data: ConfigObject = await getConfigData();
Object.freeze(data); // *** Freezes the object

export default data;
about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!