So I have an ObservableObject which has an input-binding named query and a @Published output of search results named output. It looks something like this:
class SearchViewModel: ObservableObject {
typealias Output = Result<[SearchResult], ApiError>
// `@Input` is similar to `@Published` except
// that it doesn't cause SwiftUI to re-render.
@Input var query = ""
@Published private(set) var output = Output.success([])
private let loader = SearchResultsLoader()
init() {
configureDataPipeline()
}
func configureDataPipeline() {
$query
.debounce(for: .seconds(0.5), scheduler: DispatchQueue.main)
.removeDuplicates()
// ... map to results from self.loader ...
.receive(on: DispatchQueue.main)
.assign(to: &$output)
}
}
Now I guess this is all fine, but it's not like perfectly type-safe. I'm coming from javascript with RxJS and there we would do something like:
const output$ = query$.pipe(/* transformations here */)
And the beautiful thing about that, is two things basically:
- Everything you need to know about
output$is right there in its declaration. You don't need to look for other mentions ofoutput$to determine whatoutput$is and how it behaves. - Because
output$is aconstyou can rest assured thatoutput$will never be changed into something other than what it was declared as.
I would really like it if I can get these same things in my Swift code. Is that possible? Maybe by writing my own property wrapper that slightly differs from @Published in that it accepts an AnyPublisher and then internally assigns it? Or would that interfere with using the property in SwiftUI?
Or is this whole thing a fool's errand?
What seems closest to the RxJS you posted is something along these lines:
You loose the ability to handle changes to "output" using Swift UI's syntax sugaring but you could use an
onReceivebased onoutputto respond to changes.