Skip to content

Repository files navigation

@baked-dev/async-class

Small utility to add async constructors to JavaScript/TypeScript

Install

npm

npm i @baked-dev/async-class --save-dev

yarn

yarn add @baked-dev/async-class --dev

pnpm

pnpm i @baked-dev/async-class --save-dev

Usage

TypeScript

/** * add the parameter types of the construct method as a tuple as the generic for AsyncClass. * (these types can not be Inferred from usage in the construct function at the moment) */classTestextendsAsyncClass<[string]>{publictest="asd";/**  * the construct method replaces the constructor and should be async. * without a custom constructor the parameters of the constructor  * will match this construct method. * has to be a member method as it needs to be available before super() * is called */protectedasyncconstruct(test: string){console.log(test);awaitnewPromise((res)=>setTimeout(res,1000));}publiclog=async()=>{awaitthis;// wait for contruction to finishconsole.log(this.test);};}constmain=async()=>{constawaitable=newTest("hallo");// get the "async constructor"consttest=awaitawaitable;// await the class "construction"consttest2=awaitawaitable;// can be awaited multiple timesawaitable.then(test3=>{test3.log();// -> "asd"});// can be chainedconsttest4=awaitnewTest("hallo2");// await directlyconsole.log(test===test2);// -> trueconsole.log(testinstanceofTest);// -> truetest.test="123";test.log();// -> "123"}main();

JavaScript

the same but without types

How?

AsyncClass class implements the Promise interface.

exportabstractclassAsyncClass<Cextendsany[]=[]>implementsPromise<any>

In the constructor the construct method supplied by the extending class is called and attached to this.__construct:

constructor(...args: C){this.__construct=this.construct(...args);}

.catch and .finally just proxy to the this.__construct:

publiccatch<TResult=never>(onrejected?:
|((reason: any)=>TResult|PromiseLike<TResult>)|null|undefined): Promise<any>{returnthis.__construct.catch(onrejected);}publicfinally(onfinally?: (()=>void)|null|undefined): Promise<any>{returnthis.__construct.finally(onfinally);}

.then is intercepted and resolves with a proxied instance:

publicthen<TResult1=any,TResult2=never>(onfulfilled: (value: ResolvedInstance<this>)=>TResult1|PromiseLike<TResult1>,onrejected?:
|((reason: any)=>TResult2|PromiseLike<TResult2>)|null|undefined): Promise<TResult1|TResult2>{returnthis.__construct.then(()=>{returnonfulfilled(this.__proxy);},onrejected);}

The proxied instance of this removes the Promise and internal Interfaces, else this would result in an infinite loop as Javascript eagerly awaits promises:

privatereadonly __proxy: ResolvedInstance<this>=newProxy(this,{get: (target,prop)=>{if(typeofprop==="string"&&AsyncClass.hiddenProps.includes(prop))returnundefined;elsereturnthis[propaskeyoftypeoftarget];},has: (target,prop)=>{if(typeofprop==="string"&&AsyncClass.hiddenProps.includes(prop))returnfalse;returntarget.hasOwnProperty(prop);},ownKeys: (target)=>{returnObject.keys(target).filter((key)=>!AsyncClass.hiddenProps.includes(key));},});

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages