Open alinnert opened 6 years ago
This seems good to me but we'll have to explore tradeoffs.
FWIW: I thought the purpose of from
was to be able to identify things like thennables, iterables, et al and convert them to Observables. That's what we're doing in RxJS
I think it would make sense to allow any object to be consumed by Observable.from
as long as it implements a specific interface, and Symbol.observable
looks like the right way, just like Symbol.iterator
for iterable objects.
Given that Array.from
doesn't require a single specific interface (It will handle both Iterables and ArrayLike), I don't think Observable.from
should either. Observable from should work for Symbol.observable
interface, Symbol.iterator
interface and thennables (Promises) at the very least. Probably should work with Symbol.asyncIterator
as well.
@benlesh I'm not sure about thenables. From a language (rather than library) standpoint, I think it makes more sense to stick to our "observable or iterable" generic interfaces.
@zenparsing I'm with you, it would be great if all of these types standardized on symbol interfaces. But Promise hasn't. And Array.from
doesn't. It's probably good to stay consistent, because anything we can convert to an Array, should be convertible to an Observable.
The precedent is that Array takes { length: number }
interface. I think that function arguments
has Symbol.iterator
implemented now (as a spec), but Array still supports { length }
.
Currently RxJS supports:
Symbol.observable
Symbol.iterator
Array
{ length: number, [key: number]: any }
"ArrayLike"{ then: Function }
"thennable" (yay, the Promise API)With plans to support Symbol.asyncIterator
Note that the non-symbol interfaces simply predate symbols - there is no magical reason there is no promise "symbol". I do however think Observable.from
should work with thennables
since the usage is common :)
Array.from
solves a very array-specific problem: converting iterables or array-likes into arrays. We don't need to solve this array-specific problem in Observable.from
. Users can do:
let observable = Observable.from(Array.from({ length: 1, 0: 'value' }))
Likewise with non-Promise "thenables":
let observable = Observable.from(Promise.resolve(thenable))
It's more flexible and maintainable to stick to the generic symbol interfaces unless there's a good reason not to.
Likewise with non-Promise "thenables":
let observable = Observable.from(Promise.resolve(thenable))
I'm out of the loop maybe... What would Observable.from check for if not "thennability"? instanceof Promise
? Wouldn't that mean it wouldn't work with Bluebird, RSVP, et al?
Is someone planning on proposing Symbol.promise
somewhere? If so, I'm all for it, honestly. I think symbols are great for interop.
Is someone planning on proposing Symbol.promise somewhere? If so, I'm all for it, honestly. I think symbols are great for interop.
I don't think so - honestly then
works pretty great. I'm also in favor of checking for then
rather than instanceof Promise
for Symbol.observable
(languages like C# that have private methods and nominal types have also opted for the same structural interface with GetAwaiter
vs is Task
)
I think it would be cool if we reclaimed then
as a usable method name, personally... but that's me.
What would Observable.from check for if not "thennability"? instanceof Promise? Wouldn't that mean it wouldn't work with Bluebird, RSVP, et al?
Well, I was thinking that Promise.prototype would have a Symbol.observable
method, but perhaps it would be better to avoid any circularity between Promise and Observable.
I couldn't find anything on this topic. Does this proposal also cover implementing
Symbol.observable
in existing objects?I'd like to see it implemented on
Promise.prototype
for example. This way you could convert anyPromise
into anObservable
. Similar to RxJS'Observable.fromPromise(new Promise(...))
:Typical use case:
flatMap
might be implemented manually or later, just likemap
andfilter
.