2
votes

In JavaScript in can sometimes be useful to use Promise.all to re-use some bit of data in a chain of asynchronous operations like so:

logMeIn()
.then(token => {
  return Promise.all([
    token,
    fetchProfile(token)
  ])
})
.then(([token, profile]) => {
  return getAvatar(token, {userId: profile.id})
})
// etc...

As we can see, the second then resolver needs the result of the first resolver but also still requires the token. One way would be to nest the second then call inside the first but this can get ugly and in a long chain it's no better then the callback hell promises where designed to mitigate.

Using Promise.all() allows us to re-use data from earlier resolvers and pass them down the chain.

This all works great but TypeScript flips out when you try and do this with errors like this:

Argument of type '(string | Promise<Something>)[]' is not assignable to parameter of type 'IterableShim<Something | PromiseLike<Something>>'. Types of property '"es6-shim iterator"' are incompatible.
Type '() => IterableIteratorShim<string | Promise<Something>>' is not assignable to type '() => Iterator<Something | PromiseLike<Something>>'.

Is there a way in TypeScript that the above can be done, preferably whilst retaining type safety?

1
Notice there are many other solutions for that general problem. Doesn't TypeScript already support async/await?Bergi
@Bergi It does, although this particular pattern would likely be supported when TypeScript gets variadic typesMadara's Ghost

1 Answers

0
votes

You can try to specify return type explicitly:

logMeIn()
    .then<[Token, Profile]>(token => Promise.all([token, fetchProfile(token)]))
    .then(([token, profile]) => getAvatar(token, { userId: profile.id }))