6

In my project, I have numerous functions which asynchronously fetch data from the underlying data source and return result as a Promise<T>, where T is an optional model object. I need to fetch 2 different, independent objects in parallel. For that I've tried to use when(resolved: [Promise<T>]) function:

let userPromise: Promise<User> = fetchUser(with: userID)
let documentPromise: Promise<Document> = fetchDocument(with: documentID)

when(resolved: [userPromise, documentPromise]).done {
...
}

But I'm getting an error Cannot invoke 'when' with an argument list of type '(resolved: [Any])'. I've tried to assign promises to explicitly declared array:

let promises: [Promise<Any>] = [userPromise, documentPromise]

but now I'm getting an error that Promise<User> cannot be assigned to Promise<Any>. Frankly, I can't wrap my mind around it. What's the problem there?

P.S. To make things easier to grasp, I have created the following snippet:

func getPromise() -> Promise<String> {
   return Promise<String>.pending().promise
}

let promise: Promise<Any> = getPromise()

which produces the similar error: Cannot convert value of type 'Promise<String>' to specified type 'Promise<Any>' Any ideas how to solve it? Thanks!

Environment: PromiseKit 6.2.4, Swift 4.1, Xcode 9.4

Serzhas
  • 854
  • 12
  • 23

1 Answers1

7

when(resolved:) is declared so that it only accepts promises with the same type. Here's its signature:

public func when<T>(resolved promises: Promise<T>...)

Do you particularly need a non-rejecting when(resolved:)? Have you tried when(fulfilled:_:)? The difference is that the latter rejects as soon as one of the provided promises rejects.

If using when(fullfilled:_:) is possible then you could write something like this:

when(fulfilled: [userPromise, documentPromise])
  .done { user, document in
    // ...
  }
  .catch { error in
    // either of promises has been rejected
    print(error)
  }
Dan Karbayev
  • 2,870
  • 2
  • 19
  • 28
  • Thanks for the reply, Dan! :) `public func when(resolved promises: Promise...)` - yeah, that's why I have tried to upcast `Promise` to `Promise`, which is a valid upcast AFAIK, but it doesn't work for some reason As to `when(fulfilled:_:)` option - it has exactly the same signature as `when(resolved:_:)`, so it doesn't work in my case as well... – Serzhas Jun 12 '18 at 05:19
  • @Serzhas nope, "resolved" version of `when` function has the following signature: `when(resolved promises: Promise...) -> Guarantee<[Result]>` whereas "fulfilled" version is this one: `when(fulfilled pu: U, _ pv: V) -> Promise<(U.T, V.T)> where U : Thenable, V : Thenable`. Notice the difference: `resolved` accepts a variadic parameter which is the same as passing an array with items of the same type. On the other hand, `fulfilled` accepts two parameters of possibly but not necessary different types. – Dan Karbayev Jun 12 '18 at 20:01
  • Thanks, Dan! I will try "fulfilled" version with variadic parameter :) – Serzhas Jun 14 '18 at 11:26
  • Dan, would be great if you could change your array of two comments to a variadic array - your answer with that would have gone smoothly, I spent a lot of time using the code above as an example before changing successfully to variadic parameters. – David H Nov 02 '22 at 15:24