How to change the result type of a Promise< > in TypeScript
since returning Promise< void > is becoming quite a common pattern for me
You can use a type assertion
initialiseApp( ): Promise< void >
{
let promises: Promise< any >[ ] = [ ];
promises.push( this.initLanguageStrings( ) );
promises.push( this.initModelData( ) );
promises.push( this.initUserInfo( ) );
return Promise.all( promises ) as Promise<void>;
}
Note : when you use an assertion you are essentially lying to the compiler in this case. Be careful about bugs where the compiler thinks one thing and the runtime sees another.
return Promise.all( promises ).then( ( ) => { } );
This is the right way to do it. The runtime matches what the compiler has inferred. If you want a Promise<void>
... then make a Promise<void>
which is what this code sample does.
Related videos on Youtube
Kevmeister68
Updated on June 04, 2022Comments
-
Kevmeister68 almost 2 years
For some Typescript methods I build, often I need the asynchronicity of a promise but I do not require the promise to return a value (conceptually speaking). A simple example might be calling an initLanguageStrings( ) method to load up language strings used by an application. The language strings are placed into a global structure but the promise is still necessary to ensure the application does not continue until after the language strings are loaded.
Multiple this scenario two or three times and I then tie all of the initialisation work into a set of promises that collectively must all be completed before continuing. I therefore use Promise.all, like so (example):
initialiseApp( ): Promise< void > { let promises: Promise< any >[ ] = [ ]; promises.push( this.initLanguageStrings( ) ); promises.push( this.initModelData( ) ); promises.push( this.initUserInfo( ) ); return Promise.all( promises ); }
The above code won't actually compile (TS1.5/1.6) because Promise.all( ) returns Promise< any[ ] > not Promise< void >.
So what I end up writing is this:
return new Promise( ( resolve, reject ) => { Promise.all( promises ) .then( ( dummy: any[ ] ) => { resolve( ); } ); } );
I believe this is semantically the correct approach, because the "implementation" actually remains hidden, and the "inner promise" (from Promise.all) never "escapes" to the caller of initialiseApp( ).
But on the other hand I find this approach ugly, and would like to find a nicer way to do this, since returning Promise< void > is becoming quite a common pattern for me.
Is there a better way to achieve what I am trying to do?
The compiler will permit:
return Promise.all( promises ).then( ( ) => { } );
But it too strikes me as "tricky" and ugly.
-
Kevmeister68 over 8 yearsThe downside I see to using a cast (type assertion) is that not only are we lying to the compiler, but the result "bleeds out" of the function to the caller. In other words, the caller of initialiseApp will in fact receive the any[ ] from Promise.all even though the method says nothing should be returned.