How can you have different return types for a flatMap when using Swift Combine? I have my first publisher, which emits a value and then I flatMap that to transform it into a new publisher. However, based on the original value, I might need to have a different publisher that returns a different type.
I've added a basic example below.
import Combine
class Testing{
var subscriptions = Set<AnyCancellable>()
func getTestScore()->AnyPublisher<Int, Never>{
return Just(80).eraseToAnyPublisher()
}
func congratulate()->AnyPublisher<String, Never>{
return Just("Good Job!").eraseToAnyPublisher()
}
func getGPA()->AnyPublisher<Double, Never>{
return Just(2.2).eraseToAnyPublisher()
}
init() {
getTestScore()
.flatMap{ score in
if score < 70{
return self.getGPA()
} else{
return self.congratulate()
}
}
.sink { _ in } receiveValue: { value in
print(value)
}.store(in: &subscriptions)
}
}
let testing = Testing()
As New Dev said, returning conditional data types is not possible - unless you don't want to erase the type to Any
.
My proposal is to create one dedicated publisher which emits if the score exceeds (or falls below) a certain limit. Now use your new publisher to create two separate, type safe, pipelines. I'm aware that you asked to use just one pipeline. However, I think this approach will give you more benefits.
Please find my working example below:
import Combine
class Testing{
var subscriptions = Set<AnyCancellable>()
func getTestScore()->AnyPublisher<Int, Never> {
return Just(80).eraseToAnyPublisher()
}
func congratulate()->AnyPublisher<String, Never> {
return Just("Good Job!").eraseToAnyPublisher()
}
func getGPA()->AnyPublisher<Double, Never> {
return Just(2.2).eraseToAnyPublisher()
}
init() {
let scoreExceedsLimit: AnyPublisher<Bool, Never> = getTestScore()
.map { $0 >= 70 }
.eraseToAnyPublisher()
scoreExceedsLimit
.filter { $0 == true }
.flatMap { _ in self.congratulate() }
.sink(receiveValue: { value in
print("first pipeline: \(value)")
})
.store(in: &subscriptions)
scoreExceedsLimit
.filter { $0 == false }
.flatMap { _ in self.getGPA() }
.sink(receiveValue: { value in
print("second pipeline: \(value)")
})
.store(in: &subscriptions)
}
}
let testing = Testing()