What I have
I have one class that executes in Its constructor only async code and other code that depends on async code result. According to some answers, to execute asynchronous code in class constructor I can follow one of two paths, run async code on init method or use an static async factory function.
Whichever path I take, I have to create some class properties with async operation result.
What I've tried:
1. Create static async factory function
class MyClass {
private constructor() {
// No async calls here
}
static async create (
someParameter,
anotherParameter,
) {
const myClass = new Myclass();
const foo = await something(someParameter);
// Create some class properties with async operation result
myClass.property = foo;
return myClass;
}
}
// with this I can create a class with
const myClass = await MyClass.create(x,y)
The problem with this aproach is, if I tried to access to class properties created with async result like so: myClass.property
, TS compiler thrown an error TS2339: Property 'property' does not exist on type 'MyClass'
. The other thing is ESLint thrown an error because of empty constructor: ESLint: Unexpected empty constructor.
.
2. Use init method
With this approach, I can access to this
an asign properties to it:
class MyClass {
property: SomeType;
constructor() {
// No async calls here
}
async init (
someParameter,
anotherParameter,
) {
const foo = await something(someParameter);
// Create some class properties with async operation result
this.property = foo;
return this;
}
}
// with this I can create a class with
const currentClass = new MyClass();
const myClass = await currentClass.init(x, y);
With this approach, I create a filed to avoid the problem TS2339: Property 'property' does not exist on type 'MyClass'.
but some new problems are thrown: TS2564: Property 'property' has no initializer and is not definitely assigned in the constructor.
and the constructor empty problem continues.
The problem
With the above, I don't know what its the correct way to run asynchronous code when initialising a class and create properties with that async result. if I leave the constructor empty I get the above mentioned errors and the same happens if I create fields without a constructor.
Update 1
The specific case I am dealing with is the following:
// Current class with async code in constructor
class Api {
/*
* First Problem:
*
* I'm going to create some properties according to async result on crate/init method.
* the problem with this is TS thrown the following error:
* `S2564: Property 'auth' has no initializer and is not definitely
* assigned in the constructor.` This error is repeated for all fields. This
* properties can't be assigned in constructor because of all of them are
* created on create/init method with async result values.
*/
auth: AuthAPI;
checkout: CheckoutAPI;
cart: CartAPI;
categories: CategoriesAPI;
collections: CollectionsAPI;
products: ProductsAPI;
/* First Problem:: `ESLint: Unexpected empty constructor.`
* as I don't have any property to be created synchronously,
* I end up with an empty constructor.
*/
private constructor() {}
// Static factory function to execute async code on class initialization, this can be replaced with `init method` to get the same result: execute asynchronous code when the class is initialised.
static async create(
// Configuration values
client: ApolloClient<any>,
config: ConfigInput,
onStateUpdate?: () => any,
): Promise<Api> {
const api = new Api();
const finalConfig = {
...defaultConfig,
...config,
};
const localStorageHandler = new LocalStorageHandler();
const apolloClientManager = new ApolloClientManager(client);
const jobsManager = await JobsManager.create(
localStorageHandler,
apolloClientManager,
);
// Async classes/methods to await
const saleorState = await SaleorState.create(
finalConfig,
localStorageHandler,
apolloClientManager,
jobsManager,
);
const localStorageManager = new LocalStorageManager(
localStorageHandler,
saleorState,
);
if (onStateUpdate) {
saleorState.subscribeToNotifiedChanges(onStateUpdate);
}
// Create properties with async results
api.auth = new AuthAPI(saleorState, jobsManager, finalConfig);
api.checkout = new SaleorCheckoutAPI(saleorState, jobsManager);
api.cart = new SaleorCartAPI(
localStorageManager,
apolloClientManager,
saleorState,
jobsManager,
);
api.categories = new CategoriesAPI(client);
api.collections = new CollectionsAPI(client);
api.products = new ProductsAPI(client);
// Return the class with properties created
return api;
}
}
// Create the class and await to the result
const myApi = await Api.crate(
apolloClient,
config,
onSaleorApiChange,
);
/*
* Third problem: Here I access to some properties created with async code,
* according to the comments in the class fields section,
* I'm faccing some problems with fields because if I don't have a constructor,
* the properties give me the `TS error` mentioned above, and if I remove
* the fields and use the approach number 2 in which I use the `init method`
* and access to `this`, when I am trying to access to class properties,
* I get the error `TS2339: Property 'auth' does not exist on type 'Api'.`
*/
const auth = myApi.auth()
With the concrete example above, how do I solve:
- first problem:
TS problem
withclass fields
- second problem: How to manage
empty constructor
? - third problem:
access to class properties created with async values on create/init method
after instantiating the class.