How to change the result type of a Promise< > in TypeScript

Kevmeister68 picture Kevmeister68 · Oct 6, 2015 · Viewed 10.1k times · Source

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.

Answer

basarat picture basarat · Oct 6, 2015

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.